点语法

1 - OC 设计点语法的目的就是为了让其他语言的开发者可以很快的上手该语言,点语法就是让 OC 和其他面向对象的语言很相像

注:点语法的本质是方法的调用,而不是访问成员变量。其实就是转换成相应的 setter/getter 方法,没有 setter/getter 就不能使用点语法

2 - 在 OC 中访问成员变量只有一种方式即使用 ->,且是在 @public 修饰的前提下。凡是符合系统默认的 setter/getter 书写格式的方法都可以使用点语法

3 - 如何使用点语法

// - Person.h 

1 #import <Foundation/Foundation.h>
 2 @interface Person : NSObject
 3 {
 4     int _age;
 5 }
 6 
 7 - (void)setAge:(int)age;
 8 - (int)age;
 9 
10 @end

// - Person.m 

1 #import "Person.h"
 2 @implementation Person
 3 
 4 - (void)setAge:(int)age{
 5 
 6     _age = age;// 如果写成 self.age = age,则等同 [self setAge:newAge],程序 crash
 7 }
 8 
 9 - (int)age{
10     return _age;
11 }
12 
13 @end

// - main.m

1 #import <Foundation/Foundation.h>
 2 #import "Person.h"
 3 
 4 int main(int argc, const char * argv[]){
 5     
 6     @autoreleasepool {
 7         
 8         Person *person = [[Person alloc] init];
 9         person.age = 10;     // 同 [person setAge:10]
10         
11         int age = person.age;// 同 int age = [person age]
12         NSLog(@"age is %i", age);
13         [person release];
14     }
15     return 0;
16     
17 }

property | synthesize

1 - 这两个关键字是编译器特性,可以让 Xcode 可以自动生成 getter/setter 的声明和实现!iOS 6 之后 LLVM 编译器引入property autosynthesis,即属性自动合成。换句话说,就是编译器会为每个 @property 添加 @synthesize

① @property 它可以自动生成某个成员变量的 setter/getter 的声明,比如 @property int age 会自动扩展成下面两句

- (void)setAge:(int)age;
- (int)age;

② @synthesize 帮助生成成员变量的 setter/getter 的实现,比如 synthesize age = _age 会创造一个带下划线前缀的实例变量名,同时使用这个属性生成 getter/setter 方法的实现

注:使用 @synthesize 只有一个目的,就是给实例变量起个别名,或者说为同一个变量添加两个名字

- (void)setAge:(int)age{
    _age = age;
}
- (int)age{
    Return _age;
}

2 - 在

① Xcode 4.4 版本之前的 @property 和 @synthesize

// - Person.h

#import <Foundation/Foundation.h>
@interface Person : NSObject
// 只负责声明接口,不负责实现
@property int age;
@end

// - Person.m

#import"Person.h"
@implementation Person
// 负责实现:实例变量、接口实现
@synthesize age = _age;

@end

// - main.m

#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        Person *p = [[Person alloc] init];
        [p setAge:18];
        NSLog(@"age = %d",p.age);
    }
    return 0;
}

② Xcode 4.4 版本之后的 @property 和 @synthesize

// - Person.h

1 #import <Foundation/Foundation.h>
 2 @interface Person : NSObject{
 3 
 4     // 成员变量
 5     int _age;
 6     double _weight;
 7     
 8 
 9 }
10 
11 // @property 会一并生成 setter/getter 的声明和实现
12 @property int age;
13 @property double weight;
14 @property NSString *name; // 成员变量 _name 也会自动生成
15 
16 @end

// - Person.m

#import "Person.h"

@implementation Person
// @synthesize 的功能已被 @property 所包含,可以弃用掉
@end

// - main.m

1 #import <Foundation/Foundation.h>
 2 #import "Person.h"
 3 int main(int argc, const char * argv[]) {
 4     @autoreleasepool {
 5 
 6         Person *p = [[Person alloc] init];
 7         p.age = 28;
 8         [p setWeight:110.2];
 9         [p setName:@"小白"];
10 
11         NSLog(@"age = %d,name = %@,weight = %0.2f",p.age,p.name,p.weight);
12     }
13     return 0;
14 }

注:Xcode 4.4 后 @property 就独揽了 @property/@synthesize 的功能。需要注意的是这种方式生成的成员变量是 private 的,你可以在声明成员变量的花括号中改变成员变量的作用域

3 - 当 setter/getter 方法均是手动实现时,那么编译器将不会生成成员变量且编译报错!下面进行验证

// - Person.h

1 #import <Foundation/Foundation.h>
 2 @interface Person : NSObject
 3 // 解决方式 1:同时书写两方法的话,编译器无非是不会帮我们生成成员变量。此时我们手动声明该实例变量即可
 4 {
 5   // NSString *_name;
 6 }
 7 
 8 @property (nonatomic, copy) NSString *name;
 9 - (void)setName:(NSString *)name;
10 - (NSString *)name;
11 
12 @end

// - Person.m

1 #import "Person.h"
 2 @implementation Person
 3 
 4 // 解决方式 2:使用 @synthesize 关键字
 5 @synthesize name = _name;
 6 
 7 -(void)setName:(NSString *)name{
 8 
 9     if (_name != name) {
10         _name = name;
11     }
12 }
13 
14 -(NSString*)name{
15 
16     return _name;
17 }
18 
19 @end

注:使用 @dynamic 可阻止 @synthesize 自动合成!经典的使用场景是你知道已经在某处实现了getter/setter 方法,而编译器不知道的情况

修饰属性的属性

1 - 属性三大特性

① 读写特性:readonly、readwrite;默认 readwrite

    readwrite 自动生成 setter/getter

    readonly  只会自行生成  getter

② 原子特性:atomic 原子性 、nonatomic 非原子性 ; 默认是 atomic,但是在开发中一般使用 nonatomic

    atomic 会保证在多线程情况下访问实例变量是安全的,它会加上一把线程锁,在使用的时候,会比较耗费资源

    nonatomic 不能保证在多线程下是安全的

③ 语义特性:assgin、retain、copy:会决定生成 setter 方法的内部实现细节,默认是 assgin

    assgin 代表直接给实例变量赋值,但是对于对象类型会有内存问题,此特性通常适用于基本型

    retian 代表生成 setter 方法内部是有内存优化的代码,不再是直接赋值

    copy 代表生成 setter 方法内部是有内存优化的代码,不再是直接赋值,值得注意的是仅有接收 NSCoping 协议的类才能写 copy

1 #import <Foundation/Foundation.h>
 2 
 3 @interface Dog : NSObject
 4 // 重新声明 setter/getter 方法名称
 5 @property(nonatomic,retain,getter = haveName,setter = makeName:) NSString *name;
 6 // 等价如下
 7 //- (void)makeName:(NSString *)name;
 8 //- (NSString *)haveName;
 9 
10 @property(nonatomic,retain)NSString *sex;// 属性的类型决定 setter 的参数类型以及 getter 的返回值类型
11 @property(nonatomic,assign)NSInteger age;// 属性的名字决定 setter/getter 的方法名
12 @end

小结

1 - @synthesize 关键字

① @synthesize 属性明 = 实例变量名;意思是将属性的 setter/getter 方法作用于这个变量!

② @synthesize 可以指定与属性对应的实例变量,比如 @synthesize age = _myAge 当我们调用 self.age 时其实是操作的实例变量 _myAge 而不是 _age

③ 禁止 @synthesize。如果某属性已经在某处实现了自己的 setter/getter,可以使用 @dynamic 来阻止 @synthesize 自动生成新的 setter/getter 覆盖

④ 一般情况下无需对属性添加 @synthesize ,但一些特殊情形仍然需要!比如在 protocol 中声明并实现属性时,协议中声明的属性不会自动生成 setter/getter,[UIApplicationDelegate window] 就是个典型的例子