首页 > 其他 > 详细

Effective Objective -C 第二章 对象、消息、运行期(1)

时间:2017-03-01 12:04:11      阅读:249      评论:0      收藏:0      [点我收藏+]

"对象"就是“基本构造单元”,开发者可以通过对象来存储并传递数据

在对象之间传递数据并执行任务的过程就叫做"消息传递"。

"属性"在OC中的作用就是封装对象中的数据。OC对象通常会把其所有需要的数据保存为各种实例变量。实例变量一般通过“存取方法”来访问,“获取方法”用于读取变量值,而”设置方法“用于写入变量值。

  • 属性特质

  原子性:在默认情况下,由编译器所合成的方法会通过锁定机制确保其原子性(atomicity)。如果设定属性具备nonatomic特质,则不使用同步锁。

  读/写权限:

    具备readwrite(读写)特质的属性拥有"获取方法(getter)"与"设置方法(setter)"。若该属性有@synthesize实现,则编译器会自动生成这两个方法。

    具备readonly(只读)特质的属性仅拥有获取方法,只要当该属性有@synthesize实现时,编译器才会为其合成获取方法。

  内存管理语义:

  1. assign "设置方法"只会执行针对"纯量类型"(例如:CGFlost或NSInteger等)的简单赋值操作。
  2. strong 次特质表明该属性定义了一种"拥有关系"。为这种属性设置新值时,设置方法会先保留新值,并释放旧值,然后再将新值设置上去。
  3. weak 次特质表明该属性定义了一种"非拥有关系"。为这种属性设置新值时,设置方法既不保留新值,也不释放旧值。此特质通assign类似,然而在属性所指的对象遭到摧毁时,属性值也会清空。
  4. unsafe_unretained 此特质的语义和assign相同,但是他适用于"对象类型",该特质表达一种"非拥有关系",当目标对象遭到摧毁时,属性值不会自动清空,这一点与weak有区别。
  5. copy 此特质所表达的所属关系与strong类似。然而设置方法并不保留新值,而是将其"拷贝"。
  6. getter=<name> 指定"获取方法"。
  7. setter=<name> 指定"设置方法"。

 

  • 在对象内部尽量直接访问实例变量(在读取实例变量的时候建议尽量采用直接访问的形式,而在设置实例变量的时候通过属性来做)

  // 用实例变量完成获取和设置方法

  1. 在对象内部读取数据是,应该直接通过实例变量来读,而写入数据时,则应通过属性来写。
  2. 在初始化方法及dealloc方法中,总是应该直接通过实例变量来读写数据。
  3. 有时会使用惰性初始化技术配置某份数据,这种情况下,需要通过属性来读取数据。
  • 理解"对象等同性"这样概念
  1. 按照==操作符比较出来的结果未必是我们想要的,因为该操作比较的是两个指针本身,而不是其所指的对象。应该使用NSObject协议中声明的"isEqual:"方法来判断两个对象的等同性。NSString类实现了一个自己独有的等同性判断方法,名叫"isEqualToString:"。传递给噶方法的对象必须是NSString,否则结果未定义(undefined)。调用该方法比调用"isEqual:"方法快,后者还要执行额外的步骤,因为它不知道受测对象的类型。
  2. NSObject类对这两个方法的默认实现是:当且仅当其"指针值"完全相等时,这两个对象才相等。
  3. 可以用方法-(NSUInteger)hash;也可以实现等同性的比较。根据等同性的约定:若两对象相等,则其哈希码(hash)也相等,但是两个哈希码相同的对象却未必相等。
  4. 特定类所具有的等同性判定方法 例如"isEqualToArray:"、"isEqualToDictionary:"。在编写判定方法时,也应一并覆写"isEqual:"方法。
  5. 等同性判定的执行深度。 NSArray的检测方式为先看两个数组所含对象个数是否相同,若相同,则在每个对应位置的两个对象身上调用其"isEqual:"方法。如果对应位置上的对象均相等,那么这两个数组就相等,这就是"深度等同性判断"。
  6. 容器中可变类的等同性。把某对象放入collection之后改变其内容将会造成collection中的值改变。
  7. 若想检测对象的等同性,请提供"isEqual:"与hash方法;相同的对象必须具有相同的哈希码,但是两个哈希码相同的对象却未必相同;不要盲目地逐个检测每条属性,而是应该依照具体需求来置顶检测方案;编写hash方法时,应该使用计算速度快而且哈希码碰撞几率低的算法。
  • 以"类族模式"隐蔽实现细节
  1. "类族"是一种很有用的模式,可以隐蔽"抽象基类"背后的实现细节。
  2. 创建类族:
     1  typedef NS_ENUM(NSUInteger,EmployeeType){
     2      EmployeeTypeDeveloper,
     3       EmployeeTypeDesigner,
     4      EmployeeTypeFinance  
     5  };
     6 
     7 @interface  Employee : NSObject
     8 
     9 @property (copy) NSString *name;
    10 @property NSUInteger salary;
    11 
    12 + (Employee *)employeeWithType:(EmployeeType){
    13   switch(type){
    14      case EmployeeTypeDeveloper:
    15           return [EmployeeTypeDeveloper new];
    16           break;
    17      case EmployeeTypeDesigner:
    18           return [EmployeeTypeDesigner new];
    19           break;
    20    case EmployeeTypeFinance:
    21           return [EmployeeTypeFinance new];
    22           break;
    23 
    24    }
    25 }
    26 - (void) doADaysWork{
    27 }

   每个“实体子类”都是从基类继承而来。

  

 1 @interface EmployeeDeveloper : Employee
 2 
 3 @end
 4 
 5 @implementation EmployeeDeveloper
 6 - (void) diADaysWork{
 7      [self writeCode];
 8 }
 9 
10 @end

  基类实现了一个“类方法”,该方法根据待创建的雇员类别分配好对应的雇员实例。这种“工厂模式”是创建类族的办法之一。

  3. Cocoa 里的类族

 例如 NSArray,NSDictionary,这都是类族。

 给某个类族增加子类,需要注意的几条规则:

  1. 子类应该继承自类族中的抽象基类。例如 若要编写NSArray 类族的子类,则需要令其继承自不可变数组的基类或可变数组的基类。
  2. 子类应该定义自己的数据存储方式。子类必须用一个实例变量来存放数组中的对象。NSArray本身只不过是包在其他隐藏对象外面的壳,它仅仅定义了所有数族都需要具备的一些接口。
  3. 子类应当覆写超类文档中指明需要覆写的方法。

要点: 1. 类族模式可以把视线细节隐藏在一套简单的公共借口后面;

    2. 系统框架中经常使用类族;

      3. 从类族的公共抽象基类中继承子类时要当心,若有开发文档,则应首先阅读。

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

    有时需要在对象中存放相关信息,这时我们通常会从对象所属的类中继承一个子类,然后改用这个子类对象。关联对象:可以给某个对象关联许多其他对象,这些对象通过“键”来区分。

        技术分享

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

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

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

用法例子:

  

 1 #import <objc/runtime.h>
 2 
 3 static void *MyAlertViewKey = @"MyAlertViewKey";
 4 
 5 - (void)askUserAQuestion{
 6     
 7    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Question" 
 8                                                                message:@"弄啥呢?"
 9                                                                delegate:self 
10                                                          cancelButtonTitle:@"Cancel"
11                                                          otherButtonTitles:@"Continue",nil];
12 
13      void (^block)(NSInteger) = ^(NSInteger buttonIndex){
14                       if(buttonIndex == 0){
15               [self doCancle]
16                     } else{
17               [self doContinue]}
18         };
19 
20      objc_setAssociatedObject(alert,MyAlertViewKey,block,BJC_ASSOCIATION_COPY);
21       [alert show];
22 
23 }  
24 
25 - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
26   void (^block)(NSInteger) = objc_getAssociatedObject(alertView,MyAlertViewKey);
27 block (buttonIndex);
28 }  
  1. 可以通过“关联对象”机制来把两个对象连起来。
  2. 定义关联对象时可指定内存管理语义,用以模仿定义属性时所采用的“拥有关系”与“非拥有关系”。
  3. 只有在其他做法不可行时才应选用关联对象,因为这种做法通常会引入难以查找的bug.

 

 

 

 

 

 

 

 

 

 

    

Effective Objective -C 第二章 对象、消息、运行期(1)

原文:http://www.cnblogs.com/huangF/p/6390223.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!