Objective-C 学习笔记大杂烩

OC学习笔记

属性(property)和成员变量

  • 属性为了让类外可以访问成员变量
  • 属性就是成员变量的外部接口
  • 在类内调用成员变量而不是属性,属性是给类外使用的
  • 在新版本的iOS SDK中,只要声明了属性系统就会自动生成成员变量。
    例如:
@property(nonatomic,strong)NSString *people;

则在类内可以直接调用成员变量_people

  • 属性可以用点(.)语法调用

方法

  • []调用方法,详情如下
 @interface People : NSObject
 /*
 声明方法
 - 、+ 是方法的类型,(-代表对象方法(用对象名来调用),+代表类方法(用类名来调用)),
(加号方法和减号方法可以互相调用,但是需要类名和实例化变量,加号方法不能调用成员变量。)
 */
 - (void)report;
 + (void)report;
 @end

在对象方法中调用类方法,和在类方法中调用对象方法

 /* .m文件对方法的实现 */
 - (void)report
 {
     NSLog(@"- 号: report");
     [People report1];
 }

 + (void)report1
 {
     NSLog(@"+ 号:report1");
     [[People alloc] report];
 }
  • 对象方法中可以调用成员变量
  • 初始化方法
//初始化方法
- (id)init;
/* id类型是万能类型,可以返回各种类型对象 */
-(instancetype)init;
/* instancetype代表当前类的类型 */

对于选择哪个,在初始化方法中都行,对于其他的一些方法,填id会导致错误,一般填写instancetype。

关于id和instancetype

如下代码

@interface NSArray
  + (id) creatAnArray;
@end

当我们用如下方式初始化NSArray时:

[NSArray creatAnArray];

得到的返回类型将和方法声明的返回类型一样,是id;

但当我们将id改为instancetype时:

@interface NSArray
+ (instancetype) creatAnArray;
@end

再用刚同样的方式初始化时:

[NSArray creatAnArray];

得到的返回类型将会和方法所在类的类型相同,是NSArray*;

id和instancetype的区别

  1. id在编译的时候不能判断对象的真实类型

    instancetype在编译的时候可以判断对象的真实类型

  2. 如果init方法的返回值是instancetype,那么将返回值赋值给一个其它的对象会报一个警告

    如果是在以前, init的返回值是id,那么将init返回的对象地址赋值给其它对象是不会报错的

  3. id可以用来定义变量, 可以作为返回值, 可以作为形参

    instancetype只能用于作为返回值,例如:

    //err,expected a type  
    - (void)setValue:(instancetype)value  
    {  
       //do something  
    }  
    
    就是错的,应该写成:
    - (void)setValue:(id)value  
    {  
       //do something  
    }

    参考自iOS instancetype 和 id 区别详解

封装

  • 修饰符的问题
@interface MyClass : NSObject
{
    //成员变量访问修饰符的问题
    //默认 - 受保护

    //公有 - 在类内类外都可以使用
    @public
    int _classInt;  /*声明为公有成员类型,则在类外也可以被调用,但是要用指向(->)调用*/

    //私有 - 在类内可以使用,类外无法调用并且不能被继承
    @private

    //受保护 - 在类内可以使用,类外无法调用并且可以被继承
    @protected

    //框架权限 - 在框架内相当于受保护,在框架外相当于私有
    @package
}
@property(nonatomic,strong)NSString *className;
//方法是没有访问修饰符的同C语言一样
- (void)report;
@end

继承

  • OC中没有多继承,要实现多继承要通过协议来实现。
  • 父类中的私有成员变量是无法继承使用的,而如果子类继承了父类的方法,方法中有队私有变量的操作以及打印,那我们是可以看到的,但是我们不可以在子类中直接调用私有变量。
  • 如果父类中的方法没有写声明则子类无法继承父类中对应的方法。

多态

  • OC中不支持方法的重载

注释

  • 使用 /** 文本 **/ 的注释格式(快捷键cmd+alt+/)可以对方法等进行快速注释。

修饰符

在苹果引入ARC之后,修饰符有所增加

存取类型

  1. 任何属性都可以声明为readwrite或readonly,且默认设置为readwrite
  2. readwrite:程序自动创建setter/getter方法。
  3. readonly:程序之创建getter方法。
  4. 自定义setter/getter方法 : @propery(setter=setId,getter=getId) int id;

原子性

  1. atomic:生成的setter/getter操作为原子性的操作,执行性能较低(系统默认)。
  2. noatomic:生成的setter/getter操作为非原子性的操作,执行性能较高。一般推荐手动设置为该属性。

生命周期

MRC
  1. assign: 简单赋值,不更改引用计数。一般用于基础类型的数据(NSInteger)和C语言类型数(int,float,double,char,bool)。是MRC模式下的默认值。
  2. copy: 会拷贝传入的对象(即创建一个引用计数为1的新对象,但是内容与传入对象相同),并把新对象赋值给实例变量。常用与NSString,NSArray,NSDictionary,NSSet等。
  3. retain: 释放旧对象,并使传入的新对象引用计数+1。此属性只能用于NSObject及其子类,而不能用于Core Foundation(因为其没有使用引用计数,需要另外使用CFRetain和CFRelease爱进行CF的内存管理)。
ARC

ARC中加入以下修饰符

  1. strong: 强引用,类似于retain。要求保留传入的对象,并放弃原有对象。一个对象只要被至少一个强引用指向,则其不会被释放,而当没有强引用指向时则会被释放。在ARC下是对象类型的默认值。

  2. weak: 弱引用,要求不保留传入的属性(既不会使传入的对象引用计数+1)。类似于assign,但与assign不同的是,当它们指向的对象被释放后,weak会被自动置为nil,而assign则不会,所以assign会导致“野指针”的出现,weak可以避免悬空指针。

  3. unsafe_unretained: 其实质等同于assign。与weak的区别就是指向的对象如果被释放,其不会被置为nil,而导致悬空指针的出现。它是ARC模式下非对象属性的默认值。

属性的默认值
  • MRC:(atomic, readwrite, assign)
  • ARC下对象类型属性:(atomic, readwrite, strong)
  • ARC下非对象类型:(atomic, readwrite, unsafe_unretained)

关于copy和strong

  • 使用copy修饰immutable类型,使用strong修饰mutable类型

引用一下一句话:

For attributes whose type is an immutable value class that conforms

to the NSCopying protocol, you almost always should specify copy

in your @property declaration. Specifying retain is something you

almost never want in such a situation.

举个例子:

@interface UserInfo : NSObject <NSCopying>

@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;

@end
//main 函数中
NSMutableString *mutableFirstName = [NSMutableString stringWithFormat:@"张"];
NSMutableString *mutableLastName = [NSMutableString stringWithFormat:@"全蛋"];

UserInfo *my = [[UserInfo alloc] init];
my.firstName = mutableFirstName;
my.lastName  = mutableLastName;
NSLog(@"全名:%@%@", my.firstName, my.lastName);
// print: 全名:张全蛋

// 改mutableFirstName 张 为 李
[mutableFirstName deleteCharactersInRange:NSMakeRange(0, 1)];
[mutableFirstName appendString:@"李"];
// 改mutableLastName 全蛋 为  没蛋
[mutableLastName appendString:@"没蛋"];
NSLog(@"全名:%@%@", my.firstName, my.lastName);
// print: 全名:张没蛋

对于immutable对象类型属性,假设该类型存在mutable版本,若使用strong修饰该属性,则将会是不安全的。比如在上述例子中,my.firstNamecopy修饰,而my.lastNamestrong修饰,当把mutable类型赋给了immutable类型(即NSMutableString赋给NSString),之后又修改mutable类型变量的值(将张改为李,全蛋改为没蛋),copy修饰的firstName不会改变,而strong修饰的lastName会随之改变。这是不希望发生的。

对于两者的setter方法的定义如下:

- (void) setFirstName:(NSString*)firstName{
  _firstName = [firstName copy];
}

- (void) setLastName:(NSString*)lastName{
  _lastName = lastName;
}

如果去掉copy,写成下面这个样子,则copy的好处将不复存在。

- (void) setFirstName:(NSString*)firstName{
  _firstName = [firstName copy];
}
  • 不是所有遵循NSCopying类型属性都应该使用copy修饰,而是对于NSStringNSDictionary等属性才需要使用copy修饰,因为它们存在mutable版本,在为属性赋值时,右值很可能是它们的mutable类型对象,若使用strong修饰则会带来不稳定因子;另外一个方面,如果属性类型不存在对应的mutable版本,则完全不用担心这点,反正你也无法在外部修改它,不稳定因子自然不存在了。(参考Objective-C copy那些事儿)
  • mutable属性类型不能用copy修饰,被修饰符copy修饰的属性,默认的setter赋值方式是_iVar = [var copy];copy方法返回的是immutable类型,将immutable对象赋值给mutable类型指针显然是不对的。

内存管理法则

  • 谁使对象的引用计数+1,不再引用时,谁就负责将该对象的引用计数-1

闭包(closure)

  • 规则:如果方法的最后一个参数是闭包,那么可以将它放在包含其参数的方法圆括号之外,如果闭包是唯一的参数,则可以完全跳过()
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值