疯狂iOS讲义笔记-合成存取方法和对象初始化

合成存取方法

从Objective-C 2.0版本开始,它自动合成了setter方法和getter方法。

让系统自动合成setter和getter方法只要如下两步。

  1. 在类接口部分使用@property指令定义属性。
  2. 在类实现部分使用@synthesize指令声明该属性。

当采用上述两个步骤合成存取方法之后,不仅会合成成对的stter和getter方法,还会自动在类实现部分定义一个与getter方法同名的成员变量。

使用@synthesize property名 [= 成员变量名];

在上面的语法格式中,@synthesize后没有属性,如果没有指定成员变量名,成员变量默认与合成的getter方法同名。

从Xcode5开始, 编译器有了自动合成机制(Auto property synthesis),只写@property就可以自动生成_property成员变量和getter、setter方法的声明和实现, 不需要写synthesize了。为了方便理解我还会加上@synthesize


当使用@property定义property时,还可以在@property和类型之间用括号添加一些额外的指示符,可使用的特殊指示符如下。

  • assign:该指定符指定对属性只是进行简单赋值,不更改对所赋的值的引用计数。
  • atomic (nonatomic):指定合成的方法是否为原子操作。
  • copy:如果使用copy指示符,当调用stter方法对成员变量赋值时,会将被赋值的对象复制一个副本,再将该副本值赋给成员变量。

copy释例:

@interface FKBooks : NSObject
@property (nonatomic) NSString* bookWithoutCopy;
@property (nonatomic, copy) NSString* bookWithCopy;
@end

@implementation FKBooks
@synthesize bookWithCopy;
@synthesize bookWithoutCopy;
@end

int main (void) {
    @autoreleasepool {
        FKBooks* books = [[FKBooks alloc] init];
        NSMutableString* str1 = [NSMutableString stringWithString:@"《疯狂iOS讲义》"];
        NSMutableString* str2 = [NSMutableString stringWithString:@"《疯狂jave讲义》"];
        [books setBookWithCopy:str1];
        [books setBookWithoutCopy:str2];
        NSLog(@"bookWithCopy:%@\nbookWithoutCopy:%@", [books bookWithCopy], [books bookWithoutCopy]);
        // 修改str1和str2字符串
        [str1 appendString:@"好耶!"];
        [str2 appendString:@"好耶!"];
        // 该代码你会看到没有使用copy的bookWithoutCopy属性也被修改
        NSLog(@"bookWithCopy:%@\nbookWithoutCopy:%@", [books bookWithCopy], [books bookWithoutCopy]);
    }
}

由于books的bookWithoutCopy属性值与str2指向同一个NSMutableString对象,因此当程序修改str2指向的NSMutableString对象时,books的bookWithoutCopy属性也会随之改变。而books的bookWithCopy属性值指向的是str1指向的NSMutableString对象的一个副本,因此不会改变。
编译,运行程序可以看到如下输出:

2022-05-13 22:23:08.423063+0800 oc.programme[50284:1732789] 
bookWithCopy:《疯狂iOS讲义》
bookWithoutCopy:《疯狂jave讲义》
2022-05-13 22:23:08.423259+0800 oc.programme[50284:1732789] 
bookWithCopy:《疯狂iOS讲义》
bookWithoutCopy:《疯狂jave讲义》好耶!
Program ended with exit code: 0

使用点语法

前面介绍类通过@property、@synthesize合成setter和getter方法,每次设置和访问属性时都通过setter和getter方法完成。但实际上Objective-C允许使用简化的点语法访问属性和对属性赋值。

例:

#import <Foundation/Foundation.h>

@interface FKCard : NSObject
@property (nonatomic, copy) NSString* flower;
@property (nonatomic, copy) NSString* value;
@end

@implementation FKCard
@synthesize flower;
@synthesize value;
@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        FKCard* card = [[FKCard alloc] init];
        // 使用点语法设置属性
        card.flower = @"♤";
        card.value = @"A";
        // 使用点语法访问属性
        NSLog(@"我的扑克牌:%@ %@", card.flower, card.value);
    }
}

输出为:

2022-05-14 21:18:13.273380+0800 oc.programme[51086:1769514] 我的扑克牌:♤ A
Program ended with exit code: 0

对象初始化

1. 为对象分配空间

创建对象,需要调用该类的alloc类方法来分配内存空间,实际上,这个alloc方法来自NSObject。

当程序通过某个类的方法时,系统帮我们完成如下事情。

(1)系统为该对象的所有实例变量分配内存空间。
(2)将每个实例变量的内存空间都重置为0。

2. 初始化方法与对象初始化

NSObject提供的init方法虽然可以完成初始化,但它完成的只是最基本的初始化。在实际编程中我们可以提供自己的init方法(实际就是重写NSObject的init方法),以加入任意的自定义处理代码对属性执行初始化。

例:

#import <Foundation/Foundation.h>

@interface FKUser : NSObject
@property NSString* name;
@property int age;
@end

@implementation FKUser
@synthesize name;
@synthesize age;
- (id) init {
    // 调用父类的init方法,将初始化对象返回给self
    // 如果self不为nil,则基本初始化成功
    if (self = [super init]) {
        // 执行初始化
        self.name = @"小王";
        self.age = 10;
    }
    return self;
}
@end

int main(int argc, char * argv[]) {
    @autoreleasepool {
        // 创建对象并实现初始化
        FKUser* user = [[FKUser alloc] init];
        // 访问对象的成员变量
        NSLog(@"名字:%@ 年龄:%d\n", user.name, user.age);
    }
}

输出:

2022-05-14 22:00:23.502026+0800 oc.programme[51486:1786651] 名字:小王 年龄:10

Program ended with exit code: 0

3. 便利的初始化方法

前面的示例中只是重写了init方法,实际上,我们还可以为Objective-C提供更多便利的的初始化方法,这些初始化方法通常会以init开头,并允许自带一些参数。

例如下面定义FKCar接口:

@interface FKCar : NSObject
@property (nonatomic) NSString* brand;
@property (nonatomic) NSString* model;
@property (nonatomic) NSString* color;
- (id) initBrand:(NSString*) brand Model:(NSString*) model;
- (id) initBrand:(NSString*) brand Model:(NSString*) model Color:(NSString*) color;
@end

上面接口部分定义了两个自定义的initXxx方法,这两个initXxx方法可以根据参数执行自定义初始化。下面是该FKCar类实现部分:

@implementation FKCar
@synthesize brand;
@synthesize model;
@synthesize color;
- (id) init {
    // 调用父类的init方法执行初始化,并将得到的对象赋值给self
    if (self = [super init]) {
        self.brand = @"奔驰";
        self.model = @"01";
        self.color = @"白色";
    }
    return self;
}
- (id) initBrand:(NSString*) brand Model:(NSString*) model {
    // 调用本类的init方法执行初始化,并将得到的对象赋值给self
    if (self = [self init]) {
        self.brand = brand;
        self.model = model;
    }
    return self;
}
- (id) initBrand:(NSString*) brand Model:(NSString*) model Color:(NSString*) color {
    // 调用本类的initBrand: Model:方法执行初始化,并将得到的对象赋值给self
    if (self = [self initBrand:brand Model:model]) {
        self.color = color;
    }
    return self;
}
@end

如果系统中包含多个初始化方法,且初始化方法B中完全包含了初始化A,我们完全可以在初始化方法B中调用初始化方法A,这样就可以更好地进行代码复用。
下面是FKCar的测试代码:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        FKCar *car1 = [[FKCar alloc] init];
        FKCar *car2 = [[FKCar alloc] initBrand:@"宝马" Model:@"02"];
        FKCar *car3 = [[FKCar alloc] initBrand:@"奥迪" Model:@"03" Color:@"Black"];
        NSLog(@"Car1: %@ %@ %@", car1.brand, car1.model, car1.color);
        NSLog(@"Car2: %@ %@ %@", car2.brand, car2.model, car2.color);
        NSLog(@"Car3: %@ %@ %@", car3.brand, car3.model, car3.color);
    }
}

上例中三个对象分别使用了三种初始化方法,下面是运行结果:

2022-05-15 14:30:00.788498+0800 oc.programme[52518:1841626] Car1: 奔驰 01 白色
2022-05-15 14:30:00.788678+0800 oc.programme[52518:1841626] Car2: 宝马 02 白色
2022-05-15 14:30:00.788697+0800 oc.programme[52518:1841626] Car3: 奥迪 03 Black
Program ended with exit code: 0
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值