专栏名称: Cocoa开发者社区
CocoaChina苹果开发中文社区官方微信,提供教程资源、app推广营销、招聘、外包及培训信息、各类沙龙交流活动以及更多开发者服务。
目录
相关文章推荐
花果科技  ·  iOS 18.4 ... ·  22 小时前  
花果科技  ·  iOS 18.4 ... ·  22 小时前  
51好读  ›  专栏  ›  Cocoa开发者社区

ios-收集一些自认为有用的小知识

Cocoa开发者社区  · 公众号  · ios  · 2017-08-12 11:22

正文

什么情况使用 weak 关键字,相比 assign 有什么不同?


什么情况使用 weak 关键字?


在 ARC 中,在有可能出现循环引用的时候,往往要通过让其中一端使用 weak 来解决,比如: delegate 代理属性


自身已经对它进行一次强引用,没有必要再强引用一次,此时也会使用 weak,自定义 IBOutlet 控件属性一般也使用 weak;当然,也可以使用strong。


不同点:


weak 此特质表明该属性定义了一种“非拥有关系” (nonowning relationship)。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质同assign类似, 然而在属性所指的对象遭到摧毁时,属性值也会清空(nil out)。 而 assign 的“设置方法”只会执行针对“纯量类型” (scalar type,例如 CGFloat 或 NSlnteger 等)的简单赋值操作。


assign 可以用非 OC 对象,而 weak 必须用于 OC 对象


怎么用 copy 关键字?


用途:


NSString、NSArray、NSDictionary 等等经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary;

block 也经常使用 copy 关键字

block 使用 copy 是从 MRC 遗留下来的“传统”,在 MRC 中,方法内部的 block 是在栈区的,使用 copy 可以把它放到堆区.在 ARC 中写不写都行:对于 block 使用 copy 还是 strong 效果是一样的,但写上 copy 也无伤大雅,还能时刻提醒我们:编译器自动对 block 进行了 copy 操作。如果不写 copy ,该类的调用者有可能会忘记或者根本不知道“编译器会自动对 block 进行了 copy 操作”,他们有可能会在调用之前自行拷贝属性值。这种操作多余而低效。你也许会感觉我这种做法有些怪异,不需要写依然写。


copy 此特质所表达的所属关系与 strong 类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。 当属性类型为 NSString 时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个 NSMutableString 类的实例。这个类是 NSString 的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。


用 @property 声明 NSString、NSArray、NSDictionary 经常使用 copy 关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作,为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。


@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的


@property 的本质是什么?


@property = ivar + getter + setter;


下面解释下:


“属性” (property)有两大概念:ivar(实例变量)、存取方法(access method = getter + setter)。


“属性” (property)作为 Objective-C 的一项特性,主要的作用就在于封装对象中的数据。 Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实例变量一般通过“存取方法”(access method)来访问。其中,“获取方法” (getter)用于读取变量值,而“设置方法” (setter)用于写入变量值。这个概念已经定型,并且经由“属性”这一特性而成为 Objective-C 2.0 的一部分。 而在正规的 Objective-C 编码风格中,存取方法有着严格的命名规范。 正因为有了这种严格的命名规范,所以 Objective-C 这门语言才能根据名称自动创建出存取方法。其实也可以把属性当做一种关键字,其表示:

编译器会自动写出一套存取方法,用以访问给定类型中具有给定名称的变量。 所以你也可以这么说:


@property = getter + setter;


例如下面这个类:


@interface Person : NSObject

@property NSString *firstName;

@property NSString *lastName;

@end


上述代码写出来的类与下面这种写法等效:


@interface Person : NSObject

- (NSString *)firstName;

- (void)setFirstName:(NSString *)firstName;

- (NSString *)lastName;

- (void)setLastName:(NSString *)lastName;

@end


更新:


property在runtime中是objc_property_t


定义如下:


typedef struct objc_property *objc_property_t;


而objc_property 是一个结构体,包括name和attributes,定义如下:


struct property_t { const char *name; const char *attributes;};


而attributes本质是objc_property_attribute_t,定义了property的一些属性,定义如下:


/// Defines a property attribute

typedef struct {

const char *name;

/**< The name of the attribute */

const char *value;

/**< The value of the attribute (usually empty) */

}

objc_property_attribute_t;


而attributes的具体内容是什么呢?其实,包括:类型,原子性,内存语义和对应的实例变量。


例如:我们定义一个string的property


@property (nonatomic, copy) NSString *string;


通过


property_getAttributes(property)


获取到attributes并打印出来之后的结果为


T@"NSString",C,N,V_string


其中T就代表类型,C就代表Copy,N代表nonatomic,V就代表对于的实例变量。


ivar、getter、setter 是如何生成并添加到这个类中的?


“自动合成”( autosynthesis)


完成属性定义后,编译器会自动编写访问这些属性所需的方法,此过程叫做“自动合成”(autosynthesis)。需要强调的是,这个过程由编译 器在编译期执行,所以编辑器里看不到这些“合成方法”(synthesized method)的源代码。除了生成方法代码 getter、setter 之外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,以此作为实例变量的名字。在前例中,会生成两个实例变量,其名称分别为 _firstName 与 _lastName。也可以在类的实现代码里通过@synthesize语法来指定实例变量的名字.


@implementation  Person

@synthesize firstName = _myFirstName;







请到「今天看啥」查看全文