Effective Objective-C 2.0读书笔记(二)

3.用枚举表示状态,选项,状态码

  1. 用枚举来表示状态机的状态,传递给方法的选项以及状态码等值时,能使这些状态更加通俗易懂

  2. 如果把传递给某个方法的选项表示为枚举类型,而多个选项又可同时使用,那么就将各选项值定义为2的幂,以便通过按位操作将其组合起来

enum UIViewAutoresizing {
    UIViewAutoresizingNone = 0,
    UIViewAutoresizingFlexibleLeftMargin    = 1 << 0,
    UIViewAutoresizingFlexibleWidth         = 1 << 1,
    UIViewAutoresizingFlexibleRightMargin   = 1 << 2,
    UIViewAutoresizingFlexibleTopMargin     = 1 << 3,
    UIViewAutoresizingFlexibleHeight        = 1 << 4,
    UIViewAutoresizingFlexibleBottomMargin  = 1 << 5
}
每个枚举值的二进制表示,以及对其中两个枚举值执行按位或操作之后的二进制值
  1. 用NS_ENUM与NS_OPTIONS宏来定义枚举类型,并指明其底层数据类型.这样做可以确保枚举是用开发者所选的底层数据类型实现出来的,而不会采用编译器所选的类型.

用按位或运算来操作两个枚举值时,C++编译模式的处理办法与非C++模式不一样.作为选项的枚举值经常需要用按位或运算来组合.在用或运算操作两个枚举值时,C++认为运算结果的数据类型应该是枚举的底层数据类型,也就是NSUInteger.而且C++不允许将这个底层类型"隐式转换"为枚举类本身.这时使用NS_ENUM定义枚举,而且编译器按照C++模式(也可能是Objective-C模式)编译时,则会给出以下报错:
error: cannot initialize a variable of type '枚举类型' with an rvalue of type 'int'
如果想编译这行代码,就要将按位或操作的结果显示转换.所以在C++模式下应该用另一种方式定义NS_OPTIONS宏,以便省去类型转换操作.
鉴于此,凡是需要按位或操作来组合的枚举都应使用NS_OPTIONS定义.若是枚举不需要互相组合,则应使用NS_ENUM来定义.

  1. 在处理枚举类型的switch语句中不要实现default分支.这样的话,加入新枚举之后,编译器就会提示开发者:switch语句并未处理所有枚举.


    switch语句中处理枚举类型

4.属性

关键字

1.@property
它可以自动写出一套存取方法

@interface EOCPerson : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
@interface EOCPerson : NSObject
- (NSString *)firstName;
- (void)setFirstName:(NSString *)firstName;
- (NSString *)lastName;
- (void)setLastName:(NSString *)lastName;
@end

上面两种写法对使用者来说是等效的

2.点语法
在使用了点语法之后,编译器会把点语法转换为对存取方法的调用

EOCPerson *aPerson = [EOCPerson new];
    
aPerson.firstName = @"Bob";//等同于
[aPerson setFirstName:@"Bob"];
    
NSString *lastName = aPerson.lastName;//等同于
NSString *lastName = [aPerson lastName];

3.自动合成
使用属性之后,编译器会自动编写访问这些属性所需的方法.这个过程由编译器在编译期执行,所以在编辑器里是看不到这些"合成方法"的源代码的.除了生成方法代码之外,编译器还会自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,以此作为实例变量的名字.

@interface EOCPerson : NSObject
@property NSString *firstName;
@property NSString *lastName;
@end
//生成的实例变量为_firstName和_lastName

4.@synthesize
它用来指定实例变量名字

@implementation EOCPerson
@synthesize firstName = _myFirstName;
@synthesize lastName = _myLastName;
@end
//此时的实例变量名变为了_myFirstName和_myLastName,而不是之前的_firstName和_lastName

5.@dynamic(协议的继承会用到此语法)
它会告诉编译器,不要自动创建实现属性所用的实例变量,也不要为其创建存取方法.而且,在编译访问属性的代码时,即使编译器发现没有定义存取方法,也不会报错.

更多关于dynamic关键字的知识请看:Objective-C中的@dynamic

属性特质

@property (nonatomic, readwrite, copy) NSString *firstName;

1.原子性
在默认情况下,由编译器所合成的方法会通过锁定机制确保其原子性(atomicity).如果属性具备nonatomic特质,则不使用同步锁.注意,尽管没有名为"atomic"的特质,但是仍然可以在属性特质中写明这一点,编译器不会报错(如果某属性不具备nonatomic特质,那它就是"原子的"(atomic)).

在并发操作中,如果某操作具备整体性,也就是说,系统其他部分无法观察到其中间步骤所生成的临时结果,而只能看到操作前与操作后的结果,那么该操作就是"原子的"(atomic).原子性

在开发iOS程序时应该使用nonatomic属性,因为atomic属性会严重影响性能.

2.读/写权限

  • 具备readwrite(读写)特质的属性拥有"获取方法"(getter)与"设置方法"(setter).若该属性由@synthesize实现,则编译器会自动生成这两个方法.
  • 具备readonly(只读)特质的属性仅拥有获取方法,只有当属性由@synthesize实现时,编译器才会为其合成获取方法.你可以用此特质把某个属性对外公开为只读属性,然后再"class-continuation分类"中将其重新定义为读写属性.

3.内存管理语义
属性用于封装数据,而数据则要有"具体所有权语义"(concrete ownership semantic).下面的这些特质只会影响"设置方法"

  • assign "设置方法"只会执行针对"纯量类型"(例如CGFloat或NSInteger等)的简单赋值操作
  • strong 此特质表明该属性定义了一种"拥有关系".为这种属性设置新值时,设置方法会先保留新值,并释放旧值,然后再将新值设置上去.
  • weak 此特质表明该属性定义了一种"非拥有关系".为这种属性设置新值时,设置方法既不保留新值,也不释放旧值.此特质同assign类似,然而在属性所指的对象遭到摧毁时,属性也会清空.
  • unsafe_unretained 此特质的寓意和assign相同,但是它适用于"对象类型",该特质表达一种"非拥有关系",当目标对象遭到摧毁时,属性值不会自动清空,这一点与weak有区别.
  • copy 此特质所表达的所属关系与strong类似.然而设置方法并不保留新值,而是将其"拷贝".当属性类型为NSString *时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableNSString类的实例.这个类似NSString的子类,表示一种可以修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改.所以,这是就要拷贝一份"不可变"的字符串,确保对象中的字符串值不会无意间变动.只要实现属性所用的对象是"可变的",就应该在设置新属性值时拷贝一份.

4.方法名

  • getter=<name> 指定"获取方法"的方法名.
@property (nonatomic, getter=isOn) BOOL on;
  • setter=<name> 指定"设置方法"的方法名.这种用法不太常见

在设置属性锁对应的实例变量时,一定要遵从该属性所声明的语义.

@interface EOCPerson : NSObject

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

- (id)initWithFirstName:(NSString *)firstName
               lastName:(NSString *)lastName;

@end

在实现上述初始化方法时,一定要遵循属性定义中宣称的"copy"语义

- (id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName {
    if (self = [super init]) {
        _firstName = [firstName copy];
        _lastName = [lastName copy];
    }
    return self;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容