2.对象、消息、运行期

2017-05-12  本文已影响19人  开发者老岳

第6条 理解属性这一概念


以上也是Category 为何不能添加成员变量的原因,更多参考:
http://quotation.github.io/objc/2015/05/21/objc-runtime-ivar-access.html
http://www.jianshu.com/p/2d63477c4d46
@property (retain) NSString *name;
- (void)xxx
{
    NSMutableString *mName = [@"mName" mutableCopy];
    self.name = mName;
    //接下来,如果我修改了 mName(比如在 mName上拼字符串),那么self.name也会跟着修改,
    //但开发者可能会认为 self.name 只是个 NSString 的不可变字符串,不应该被修改,但其实却是个 NSMutableString。
    //若用了copy就不会发生这种情况。
}

@property (copy) NSString *name;

- (instancetype)initWithName:(NSString *)newName
{
    self = [super init];
    if (self) {
        _name = [newName copy]; //要用copy赋值
    }
    return self;
}

@property (copy, readonly) NSString *name;

- (instancetype)initWithName:(NSString *)newName
{
    self = [super init];
    if (self) {
        _name = [newName copy];
    }
    return self;
}

第7条 在对象内部尽量直接访问成员变量

// 惰性初始化
- (Student *)student 
{
    if (!_ student) {
        _ student = [Student new];
    }
    return _ student;
}

第8条 理解“对象等同性”这个概念

NSObject 的判断俩对象是否相同的方法 isEqual:- (NSUInteger)hash 的关系:
若用 isEqual: 判断俩对象相等,则 hash 一定相同,但 hash 相同,isEqual: 判断不一定相等。

第9条 以“类族(类簇)模式”隐藏实现细节

类族一般没有 init 方法,只有一些工厂方法,它只是一个抽象的基类,中间的实现过程都隐藏了。例如UIButton,初始化没有init,而是用 buttonWithType:,其内部可能是每个类型声明了一个新的类(只是举个UIButton的例子,UIButton实际并不是类族)。
collection类(集合类)一般都是类族,包括 NSArray、NSSet和NSDictionary等,NSString、NSNumber等也是类族,以下结果返回的是NO:

NSArray *arr = [NSArray arrayWithObjects:@"abc", nil];
  if ([arr isMemberOfClass:[NSArray class]])
  {
      NSLog(@"YES");
  }
  else {
      NSLog(@"NO");
  }

第10条 在既有类中使用关联对象存储自定义数据

#import <objc/runtime.h>

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,           /** 和 assgin 等效 */
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /** strong、nonatomic */
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /** copy、nonatomic */
    OBJC_ASSOCIATION_RETAIN = 01401,       /** strong、atomic */
    OBJC_ASSOCIATION_COPY = 01403          /**< copy、atomic */
};

//设置关联
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) 

//获取关联的对象值
id objc_getAssociatedObject(id object, const void *key)

//移除指定对象的全部关联对象
void objc_removeAssociatedObjects(id object)  

UIAlertView 的 delegate 传值的时候,如果传一个 tag 还好说,如果是传多个参数,要么用一个子类继承于 UIAlertView,设置多个属性,要么就用关联对象。

第11条 理解 objc_msgSend的作用

C语言是静态绑定,若不考虑内联(inline),当你调用一个函数的时候,编译的时候编译器就知道存在这个函数了。

// OC 中的语句
id retureValue = [obj messageName:parameter];

// 转成C语言后的原型
id retureValue = objc_msgSend(obj, @selector(messageName:), parameter);

objc_msgSend 方法会在 接收者(obj)中寻找方法列表,如果找不到,就在从父类依次往上找,一直找到NSObject,如果还没找到,就开始消息转发。这个过程中,objc_msgSend并非每次都会查找,每个类会有一个缓存,这样大大提高了查找效率。

objc_msgSend_stret
objc_msgSend_fpret
objc_msgSendSuper
...
还有些内容太抽象,此处省略。

第12条 理解消息转发机制

上条介绍的消息传递,传递过程中找不到对应的方法,就会执行消息转发。消息转发分为两大阶段:

  1. 动态解析:询问接收者所属的类,能否动态添加方法。
  2. 完整的消息转发:系统请求接收者用其他方式处理消息。又分为俩阶段(就是俩回调方法),首先,先看下其他类能否处理该消息,若没有,系统会把与消息有关的全部细节封装给NSInvocation对象中,再给接收者,最后一次机会。

代码示例,建了一个EOCAutoDictionary的类,可以用该类任意存值。如:

    ECOAutoDictionary *a = [ECOAutoDictionary new];
    a.data = [NSDate date];
    NSLog(@"a.data-------%@", a.date);

第13条 用“方法调配技术”调试“黑盒方法”

method swizzling,一般用于打印一个系统方法日志,最好不要滥用,否则会让代码不易被读懂。

第14条 理解“类对象”的用意

NSObject 类在 oc 中的定义是:

@interface NSObject <NSObject> {
    Class isa  OBJC_ISA_AVAILABILITY;
}
typedef struct objc_class *Class;
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */

举个例子:

NSString *str = @"abc";

看下面的图的定义,在这个例子中,str 的 isa 指针是指向 NSString,而 NSString 也有个 isa 指针,这个指针指向的类就是 元类,说明 NSString 是该元类的一个实例对象。NSString 的类方法就是在元类里定义的。


NSProxy 简单用法:http://ios.jobbole.com/87856/
NSProxy 的作用:负责将消息转发到真正的target的代理类。举个例子,你想要卖一件二手物品,但是你并不想直接跟卖家接触(直接向target发消息),这时你去找了一个第三方,你告诉这个第三方你要买什么、出多少钱买、什么时候要等(向代理发消息),第三方再去跟卖家接触并把这些信息转告卖家(转发消息给真实的target),最后通过第三方去完成这个交易。
上一篇下一篇

猜你喜欢

热点阅读