美文网首页
Item 6 Objective-c 属性的理解

Item 6 Objective-c 属性的理解

作者: 潇游兮 | 来源:发表于2019-07-09 22:48 被阅读0次

    Item 6 Objective-c 属性的理解

    实例变量通常通过accessor方法来控制,getter方法用于读取变量,setter方法由于设置变量。oc2.0通过property来自动实现accessor方法的编写,.语法也简化了控制数据的语法。

    声明一个实例变量,你可能会:

    @interface EOCPerson: NSObject{
    @public
      NSString *_firstName;
      NSString *_lastName;
    @private
      NSString *_someIntenalData;
    }
    @end
    

    OC中通常不这么声明,这种声明对象在编译时就确定了变量的偏移量就确定了,当你添加一个变量时,问题就出现了:

    @interface EOCPerson: NSObject{
    @public
      NSString *_dateOfBirth;
      NSString *_firstName;
      NSString *_lastName;
    @private
      NSString *_someIntenalData;
    }
    @end
    

    原来指向_firstName的指针现在指向了_dataOfBirth

    图2.1 类内存偏移

    老的类定义可能存在于库中,如果连接的代码使用新的类定义,运行时就会出现不相容性。oc使用的方法是把实例变量当作一种特殊的变量,类对象来存储变量的偏移量,在运行时查找偏移量,你甚至可以在运行时给一个类添加实例变量。这就是熟知的nonfragile Application Binary Interface(ABI),实例变量同样可以在class-continuation category(implementation)中定义。

    通过对象接口中使用property来使用标准的accessor方法,声明property就相当于声明了指定的类型和名字的accessor。例如:

    @interface EOCPerson:NSObject
    @property NSString*firstName;
    @property NSString*lastName;
    @end
    

    等同与:

    @interface EOCPerson:NSObject
    -(NSString*)firstName;//getter 同名
    -(void)setFirstName:(NSString*)firstName; //setter
    -(NSString*)lastName;
    -(void)setLastName:(NSString*)lastName;
    @end
    

    使用.就相当于直接使用这些方法:

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

    编译器自动帮我们编写了这些方法,这个过程称为autosynthesis,编译器自动在类中加了俩个变量,变量名在前面添加了_,也可以修改默认的变量名通过:通常不这么做

    @implementation EOCPerson
    @synthesize firstName = _myFirstName;
    @synthesize lastName = _myLastName;
    @end;
    

    你也可以通过使用@dynamic来停止生成这个变量及方法

    @implementation EOCPerson
    @dynamic firstName, lastName;
    @end
    

    Property Attributes

    attributes可以用于控制编译器声明的accessors,使用三种attributes:

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

    可以四种类型的attribute来管理accessor

    Atomicity

    默认的,accessors包括加锁让它们atomic,如果指定nonatomic,就可以不加锁,加锁是位了防止变量被不同的线程在某一时间段被同时访问,也就造成了性能开销

    Read/Write

    readwrite可以使用getter和setter方法

    readonly只能使用getter方法,你可以声明这个属性为readonly 来让外部只读,但是在class-continuation category(.m文件接口部分)重新声明为readwrite。

    Memory-Management

    这个只影响setter方法

    assign 简单的赋值操作,一般用于纯量类型scalar type,如CGFloat NSInteger

    strong 表明属性定义了一种拥有关系,当新值被设置,首先被保留,旧的值被释放掉才设置新的值

    weak 定义了一种非拥有关系,当新的值被设置时,没有保留,旧的值也没有释放掉,有点类似assign,但是当其引用的对象被销毁时会被设置为nil。通常用于block,delegate,`NSTimer以解决循环引用带来的内存泄露问题。

    unsafe_unretained用于类型时对象类型,表明非拥有关系(unretained) ,当目标被销毁时不会设置为nil,与weak不同

    copy表明拥有关系类似strong, 不保留值,复制值,任何可能会改变的对象应该使用copy , 经常用到的就是NSString*

    Method Names

    getter=<name> 指定getter方法名,例如对于UISwitch类,属性开关的状态这样定义:

    @property(nonatomic, getter=isOn)BOOL on;
    

    setter=<name> 指定setter方法名,通常不怎么用


    看一个例子:

    @interface EOCPerson :NSMagaedObject
    @property(copy) NSString*firstName;
    @property(copy) NSString*secondName;
    -(id)initWithFirstName:(NSString*)firstName;
                lastName:(NSString*) lastName;
    @end
    

    在implementation中实现自定义的initializer时,坚持copy语义很重要:

    -(id)initWithFirstName:(NSString*)firstName;
                lastName:(NSString*) lastName
    {
            if((self=[super init])){
              _firstName =[firstName copy];
              _lastName = [lastName copy];
            }
            return self;
    }
    

    这里你可能会觉得奇怪为什么不使用属性的setter方法,不能在init中使用

    图 2.2 不懂原文

    这一段我还不理解,欢迎高人指点👈🏿

    总结

    1. @property提供了一种定义对象如何封装数据的方法
    2. 使用attributes来指明数据合理存储的方法
    3. 保证设置属性的值时遵守声明的语法
    4. 在iOS中使用nonatomic,使用atomic会影响性能

    相关文章

      网友评论

          本文标题:Item 6 Objective-c 属性的理解

          本文链接:https://www.haomeiwen.com/subject/mpdqkctx.html