编写高质量iOS的52个有效方法学习笔记(6-12)

C语言是面向过程的语言,Objective-C语言是面向对象的语言,“对象”是基本构造单元,开发者可以通过对象来存储并传递数据。对象之间传递数据并执行任务的过程称为“消息传递”。
当应用程序运行起来以后,为其提供相关技术支持的代码叫做“Objective-C 运行期环境”(Objective-C runtime),它提供了一些使得对象之间传递消息的重要函数,并且包含创建类实例的全部逻辑。

6.理解“属性”这一概念

“属性”(property)是Objective-C的一项特性,用于封装对象中的数据。

 @property (nonatomic,copy,readonly) NSString *sex;

这种写法包含了getter和setter方法,使用点语法可以来调用getter和setter方法

self.sex = @"男"; //same as:
[self setSex:@"男"];
    
NSString *sexStr = self.sex; //same as:
NSString *sexStr = [self sex];

属性的几个特性:原子性、读写性、语义性

对于atomic的属性,系统生成的 getter/setter 会保证 get、set 操作的完整性,不受其他线程影响。比如,线程 A 的 getter 方法运行到一半,线程 B 调用了 setter:那么线程 A 的 getter 还是能得到一个完好无损的对象。
而nonatomic就没有这个保证了。所以,nonatomic的速度要比atomic快。
  • Atomic

    是默认的
    会保证 CPU 能在别的线程来访问这个属性之前,先执 行完当前流程
    速度不快,因为要保证操作整体完成

  • Non-Atomic

    不是默认的
    更快
    线程不安全
    如有两个线程访问同一个属性,会出现无法预料的结果

读写特性:readwrite拥有getter(获取方法)与setter(设置方法),若该属性由@synthesize实现,则编译器会自动生成这两种方法,@synthesize在.m中声明,系统默认是有的,可以不写。
readonly(只读)仅有获取方法

语义特性

1,当把语义特性声明为assign时,setter和getter时方法内部实现

- (void)setName:(NSString *)name{

_name = name;

}

- (NSString *)name{

return _name;

}
2,当把语义特性声明为retain时,setter和getter方法内部实现

- (void)setName:(NSString *)name{

    if (_name != name) {

    [ _name release];

    _name = [name retain];

    }

}
- (NSString *)name{

    return [[ _name retain] autorelease];

}
3,当把语义特性声明为copy时,setter和getter方法内部实现

- (void)setName:(NSString *)name{

    if (_name != name) {

    [ _name release];

    _name = [name copy];

    }

}

- (NSString *)name{

    return [[ _name retain] autorelease];

}
  • 可以用@property语法来定义对象中所封装的数据
  • 通过“特性”来指定存储数据所需的正确语义
  • 在设置属性所对应的实例变量时,一定要遵循属性所声明的语义
  • 开发iOS程序时应该使用nonatomic属性,因为atomic属性会严重影响性能

7、在对象内部尽量直接访问实例变量

在对象之外访问实例变量时,总是应该通过属性来做,然而在对象内部访问实例变量时的建议是:在写入实例变量时通过其“设置方法”来做,而在读取实例变量时,则直接访问之。之所以要通过“设置方法”来写入实例变量,其首要原因在于,这样做能够确保相关属性的“语义特性”得以贯彻。
需要注意的两种情况是:1、在初始化方法中应该直接访问实例变量,因为子类可能会“覆写”(overrede)设置方法。2、懒加载。必须通过“获取方法”来访问属性,否则,实例变量就永远不会初始化。

以上获取方法指的就是点语法。

  • 在对象内部读取数据时,应该直接通过实例变量来读,而写入数据时,则应通过属性来写。
  • 在初始化方法以及dealloc方法中,总是应该直接通过实例变量来读写数据
  • 使用懒加载的话必须用点语法操作。

8、理解“对象等同性”这一概念

- (BOOL)isEqual:(id)object {
  if ([self class] == [object class]) {
      return [self isEqualToPerson:(Person *)object];
  }else{
      return [super isEqual:object];
  }
}

- (BOOL)isEqualToPerson:(Person *)person {
  if (self == object) {
      return YES;
  }
  if (![_firstName isEqualToString:person.firstName]) {
      return NO;
  }
  if (![_lastName isEqualToString:person.lastName]) {
      return NO;
  }
  if (_age != person.age ) {
      return NO;
  }
  return YES;
}
  • 若想检测对象的等同性,请提供“isEqual:”与hash 方法。
  • 相同的对象必须具有相同的哈希码,但是两个哈希码相同的对象却未必相同。
  • 不要盲目的逐个检测每条属性,而是应该依照具体需求来指定检测方案。
  • 编写hash方法时,应该使用计算速度快而且哈希码碰撞几率低的算法。

9、以“类族模式”隐藏实现细节

“类族”是一种很有用的模式,可以隐藏“抽象基类”背后的实现细节。类方法,(工厂模式)

  • 类族模式可以把实现细节隐藏在一套简单的公共接口后面。
  • 系统框架中经常使用类族。
  • 从类族的公共抽象基类中继承子类时要当心,若有开发文档,则应首先阅读。

10、在既有类中使用关联对象存放自定义数据

有时需要在对象中存放相关信息、这时我们通常会从对象所属的类中继承一个子类,然后改用这个子类对象。然而并非所有情况下都能这么做,有时候类的实例可能是由某种机制创建的,而开发者无法令这种机制创建出自己的子类实例。Object-C中有一项强大的特性可以解决这个问题,这就是“关联对象”(Associated Object)

关联类型 等效的@property
OBJC_ASSOCIATION_ASSIGN assign
OBJC_ASSOCIATION_RETAIN_NONATOMIC nonatomic,retain
OBJC_ASSOCIATION_COPY_NONATOMIC nonatomic,copy
OBJC_ASSOCIATION_RETAIN retain
OBJC_ASSOCIATION_COPY copy

下列方法可以管理关联对象:

void objc_setAssociatedObject (id object,void *key,id value,objc_AssociationPolicy policy)
此方法以给定的键和策略为某对象设置关联对象值。

id objc_getAssociatedObjects(id object,void *key)
此方法根据给定的键从某对象中获取相应的关联对象值。

void objc_removeAssociatedObjects(id object)
此方法移除指定对象的全部关联对象。

关联对象用法举例:
ios 开发时经常用到UIAlertView类,该类提供了一种标准试图,用来提示信息。但是创建的代码和处理按钮动作的代码是分开的,如:

- (void)viewDidLoad {
UIAlertView *view = [[UIAlertView alloc] initWithTitle:@"标题" message:@"消息" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"1", nil];
    [view show];
}

#pragma mark --UIAlertViewDelegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
     if (buttonIndex == 0) {
            NSLog(@"0");
        }else{
            NSLog(@"1");
        }
}

如果想在同一个类里处理多个警告信息视图,那么代码就会变得更加复杂,我们必须在delegate方法中检查传入的alertview参数,并据此选用相应的逻辑。要是能在创建视图的时候就直接把处理每个按钮的逻辑都写好,就简单多了。这可以通过关联对象来做。创建完视图后,设定一个与之关联的“块(block)”等到执行delegate方法时再将其读出来,如下:

#import <objc/runtime.h>

static void *key = @"key";
- (void)viewDidLoad {
UIAlertView *view = [[UIAlertView alloc] initWithTitle:@"标题" message:@"消息" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"1",@"2", nil];

void (^block)(NSInteger) = ^(NSInteger buttonIndex){
        if (buttonIndex == 0) {
            NSLog(@"0");
        }else{
            NSLog(@"1");
        }
 };
    
 objc_setAssociatedObject(view, key, block, OBJC_ASSOCIATION_COPY);
 [view show];
}

#pragma mark --UIAlertViewDelegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    void (^block)(NSInteger) = objc_getAssociatedObject(alertView, key);
    block(buttonIndex);
}

以这种写法,创建和处理的代码放在一起,比较方便查阅。但是,采用该方法时需要注意:块可能要捕获某些变量,也许会造成“循环引用”。

  • 可以通过“关联对象”机制来把两个对象连起来。
  • 定义关联对象时可指定内存管理语义,用以模仿定义属性时所采用的“拥有关系”与“非用有关系”。
  • 只有在其他方法不可行时才应选用关联对象,因为这种做法通常会引入难于查找的bug。

11、理解objc_msgSend的作用

id returmValue = [someObject messageName:parametter];
someObject叫做“接收者”,messageName叫做“选择子(selector)”。选择子和参数合起来称为“消息(message)”。编译器看到后将其转换成标准的C语言函数调用,所调的函数乃是消息传递机制中的核心函数,叫做objc_msgSend,其“原型”如下:

void objc_msgSend(id self,SEL cmd,……)
第一个参数是接收者,第二个参数是选择子,后续参数就是消息中那些参数,其顺序不变。

在实际开发中,大家无须担心这一问题,不过应该了解其底层工作原理。

12、理解消息转发机制

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

推荐阅读更多精彩内容