• Objective-C:属性(@property)


           苹果公司在Object-C 2.0 中引入了属性(property),它组合了新的预编译指令和新的属性访问语法。新的属性功能显著减少了必须编写的冗长代码的数量。

    1 、@property关键字

          可以使用@property关键字来声明类的属性(property),编译器能够自动生成属性名、setter方法getter方法。其中@property是在@interface块中使用。

    1.1 普通方式

          如在myClass类中有_name属性,可以实现其setter和getter方法:

     1 @interface myClass : NSObject
     2 {
     3     NSString *_name;
     4 }
     5 -(void) setName:(NSString*)name;
     6 -(NSString*) name;
     7 @end
     8 
     9 @implementation myClass
    10 -(void) setName:(NSString*)name
    11 {
    12     _name = name;
    13 }
    14 -(NSString*) name
    15 {
    16     return _name;
    17 }
    18 @end
    19 int main(int argc, const char * argv[]) {
    20     @autoreleasepool {
    21         myClass *mc = [[myClass alloc] init];
    22         [mc setName:@"hello"];
    23         NSLog([mc name]);
    24     }
    25     return 0;
    26 }

    1.2 property方式

          若使用@property关键字,则自动生成_name的成员变量,以及setName和name方法。

     1 @interface myClass : NSObject
     2 @property NSString* name;
     3 -(void) myMethod;
     4 @end
     5 @implementation myClass
     6 -(void) myMethod
     7 {
     8     NSLog(_name);
     9 }
    10 @end
    11 int main(int argc, const char * argv[]) {
    12     @autoreleasepool {
    13         myClass *mc = [[myClass alloc] init];
    14         [mc setName:@"hello"];
    15         NSLog([mc name]);
    16     }
    17     return 0;
    18 }

          在Object-C中是不能像C/C++一样使用点表达式直接访问对象中的属性,需要通过消息进行访问。但通过@property就能够直接访问对象中的属性来。比如上述的AllWeatherRadial类:

    AllWeatherRadial *a = [ [AllWeatherRadial alloc] init ];
    [a setRainHandling:23];
    NSLog(@“%f”, a.RainHandling );

    2、@synthesize关键字

           通过@property关键字声明的属性,编译器会自动生成一个实例变量,该变量的名字是在属性名前加下划线。可以使用@synthesize关键字从新指定实例变量的名字,即在@implementation文件中的某个方法使用的属性名,其有两种使用形式:

    2.1 属性名形式

          可以在@implementation文件中再此声明@property中定义的属性名,从而在@implementation中的方法只能使用@property定义的属性名,而不是在属性名前加下划线的名字。如下所示:

     1 @interface myClass : NSObject
     2 @property NSString* name;
     3 -(void) myMethod;
     4 @end
     5 @implementation myClass
     6 @synthesize name;
     7 
     8 -(void) myMethod
     9 {
    10 NSLog(name);
    11 //NSLog(_name);若是这种形式,则编译器报错
    12 }
    13 @end
    14 int main(int argc, const char * argv[]) {
    15     @autoreleasepool {
    16         myClass *mc = [[myClass alloc] init];
    17         [mc setName:@"hello"];
    18         [mc myMethod];
    19     }
    20     return 0;
    21 }

    2.2 重命名形式

          若不希望在@implementation的方法中使用属性命名的实例变量,也不希望使用下划线命名的实例变量,可以自定义自己希望的名字,同样是使用@property关键字。

    1 @implementation myClass
    2 
    3 @synthesize name=myName;
    4 
    5 -(void) myMethod
    6 {
    7     NSLog(myName); //不能使用其它形式,如使用了_name或name,则编译器会报错
    8 }
    9 @end

    3、@dynamic关键字

          若不希望编译器自动生成实例变量名和存取方法,则可以使用@dynamic关键字在@implementation文件中进行声明。

     1 @interface myClass : NSObject
     2 @property NSString* name;
     3 -(void) myMethod;
     4 @end
     5 @implementation myClass
     6 @dynamic name;
     7 -(void) myMethod
     8 {
     9     NSLog(name); //编译器将报错
    10 }
    11 @end

    4、属性特质

          @property还可以设置属性的各种特质(attribute),从而影响编译器自动生成的setter和getter方法,其使用语法为:

    @property (参数1,参数2) 类型 名字;

    表格 31 属性特质

    参数

    意义

    原子性

    atomic

    (默认)

    保证多线程访问下的安全, 但浪费系统资源, 原子性控制的默认设置.

    nonatomic

    禁止多线程,变量保护,提高性能。

    读写属性

    readwrite

    (默认)

    产生settergetter方法。

    readonly

    只产生简单的getter,没有setter, 默认的读写属性.

    内存管理

    assign

    默认类型,为简单赋值,不更改引用计数,适用于标亮数据类型(scalar type);对对象类型,同样不会改变引用计数值。

    strong

    (默认)

    该类型属性定义了一种"拥有关系",编译器会生成的setter方法会修改引用计数值。先增加新值的引用计数,再减少旧值的引用计数。

    weak

    该类型属性定义了一种"非拥有关系",编译器生成的setter方法不会修改引用计数值,即不会增加引用计数,也不会减少引用计数。此特质与assign类似,然而当该属性被系统释放时,所有引用该对象的指针都会被置为nil。

    unsafe_unretained

    该类型与assign类似,定义了一种"非拥有关系",同样不修改引用计数,当目标对象被释放时,所有引用该对象的指针不会被置为nil。

    copy

    该类型与strong类似,然而该类型的setter方法并不会增加新值的引用计数,而是会创建一个新的对象(引用计数为1)。

    retain

    与strong相对应,使用了引用计数,retain+1,release -1;当引用计数为0时,dealloc会被调用,内存被释放。

    方法名

    setter =

    指定生成setter方法的名字。

    getter =

    指定生成getter方法的名字。

     

    4.1 原子性

          atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。

    • atomicity:当属性声明为atomic时,意味着在多线程中只能有一个线程能对它进行访问,默认为原子类型
    • nonatomic:当属性声明为nonatomic时,意味着多个线程可以同时对其进行访问,所以访问速度较快.

    4.2 读写权限

    • readwrite(读写):拥有该特质的属性编译器会自动生成"获取方法"(getter)与"设置方法"(setter)。
    • readonly(只读):拥有该特质的属性编译器只生成"获取方法"(getter)。Readonly特质不生成setter方法,所以它不可以和 copy/retain/assign组合使用。

    4.3 内存管理

          内存管理的6种属性特质中,可以分为ARC和非ARC类型:

    • ARC类型:assign、strong、weak、unsafe_unretained、copy。
    • 非ARC类型:retain。

    面试题:

           1) strong与weak的区别

         strong类型的属性是一种拥有关系,即当调用strong类型属性的setter方法时,被传递参数的引用计数为+1,而原来属性值的引用计数会-1;而weak类型是一种非拥有关系,即当调用weak类型属性的setter方法时,不会修改任何引用计数,同时但weak属性被释放时,所有引用该对象的指针都会被置为nil。

          2) assign、copy及retain的区别

    • assign:该类型的属性可以理解为C++中的指针类型,即没有引用计数的概念,有可能出现访问野指针的情况。
    • retain:该类型的属性拥有引用计数,当调用该类型属性的setter方法时,会改变原来属性对象的引用计数,也会改变新传递参数的引用计数。
    • copy:该类型的属性也拥有引用计数,但当setter该属性时,不修改所传递参数的引用计数,只是复制了该参数(创建新的对象),从而新创建对象的引用计数为1。

    4.4 方法名

    • setter=<name>:指定"设置方法"的方法名,这种用法不太常见。
    • getter=<name>:指定"获取方法"的方法名。

    面试题:

          1) 在一个对象的方法里面:self.name = "object"和name ="object"的区别?

             self.name = "object"会调用对象的setName()方法,而name = "object"会直接把object赋值给当前对象的name 属性。并且若name属性声明为strong或retain类型的特质,则 self.name 的retainCount会加1,而name就不会。

  • 相关阅读:
    全站之路一路坑(3)——使用百度站长工具提交站点地图
    全站之路一路坑(2)——在Apache下部署django博客
    全栈一路坑之使用django创建博客
    Django添加模型无法数据迁移解决方法
    一款自动汇报工作的微信机器人
    微信js接口自定义分享内容
    C Primer
    皇家每羊历险记(四)——角色移动
    【转载】Spring Boot 使用SSL-HTTPS
    解决https负载报错:unable to find valid certification path to requested target
  • 原文地址:https://www.cnblogs.com/huliangwen/p/5439906.html
Copyright © 2020-2023  润新知