一赘娄、對(duì)象屬性
對(duì)于具有可變副本的屬性 (NSArray
、NSString
宏蛉、NSDictionary
)遣臼,我們傾向于將其聲明為 copy
。
比如說拾并,我們定義 Person 對(duì)象的 name
屬性的類型是 NSString
揍堰,有可能有人創(chuàng)建了一個(gè) Person 對(duì)象,并且給這個(gè)屬性賦了一個(gè) NSMutableString
的名字值 tempName
嗅义。
然后過了一會(huì)兒个榕,這個(gè)可變字符串 tempName
被變更了。
如果我們的屬性不是 copy
而是 strong
的話芥喇,隨著可變字符串 tempName
的改變西采,我們的 Person 對(duì)象也將發(fā)生改變,這不是我們希望發(fā)生的继控。
例子如下:
@interface Student : NSObject
@property (copy, nonatomic) NSString *name;
//@property (strong, nonatomic) NSString *name;
@end
- (void)testStudent{
//1.定義一個(gè)可變字符串
NSMutableString *tempName = [NSMutableString stringWithFormat:@"zhangsan"];
//2.創(chuàng)建 Student 對(duì)象并給 name 賦值
Student *student = [[Student alloc] init];
student.name = tempName;
//3.修改字符串
[tempName appendString:@"22"];
NSLog(@"1 tempName:%p - name:%p", tempName, student.name);
NSLog(@"2 tempName:%@ - name:%@", tempName, student.name);
}
使用 strong 修飾 name 時(shí)的輸出如下:
1 tempName:0x60000147f360 - name:0x60000147f360
2 tempName:zhangsan22 - name:zhangsan22
使用 copy 修飾 name 時(shí)的輸出如下:
1 tempName:0x600000af8a20 - name:0xd3c6a2453c0e238f
2 tempName:zhangsan22 - name:zhangsan
二械馆、不可變對(duì)象
如果我們需要的是不可變對(duì)象,那么我們要確保它在被創(chuàng)建后就不能再被更改武通。
我們可以通過使用初始化方法并且在接口中將我們的屬性聲明為 readonly 來實(shí)現(xiàn)這一點(diǎn)霹崎。
@interface Person : NSObject<NSCopying>
@property (readonly, nonatomic) NSString *name;
@property (readonly, nonatomic) NSDate *birthDate;
@property (readonly, nonatomic) NSInteger age;
- (instancetype)initWithName:(NSString *)name birthDate:(NSDate *)birthDate age:(NSInteger)age;
@end
#import "Person.h"
@implementation Person
- (instancetype)initWithName:(NSString *)name birthDate:(NSDate *)birthDate age:(NSInteger)age{
if (self = [super init]) {
_name = [name copy];
_age = age;
_birthDate = birthDate;
}
return self;
}
@end
現(xiàn)在我們構(gòu)建新的 Person 對(duì)象和其他的類一起工作的時(shí)候,我們知道 Person 的 name 這些值是不會(huì)發(fā)生改變的冶忱。
注意:在 Person 的初始化方法或者是 dealloc 中最好使用實(shí)例變量而不要使用屬性尾菇,因?yàn)槟銦o法確定 self 調(diào)用的到底是不是你想要的實(shí)例。
三、消息傳遞機(jī)制
消息傳遞中的發(fā)送者派诬、接收者舉例:我們創(chuàng)建的 table view 是發(fā)送者劳淆,而它的 delegate 則是接收者。
1.NSNotification
通知的獨(dú)特之處在于默赂,發(fā)送者和接收者不需要相互知道對(duì)方沛鸵,所以通知可以被用來在不同的相隔很遠(yuǎn)的模塊之間傳遞消息。
使用場景:
- 如果要在項(xiàng)目的兩個(gè)不相關(guān)的模塊中傳遞消息時(shí)缆八,通知機(jī)制是非常好的工具曲掰。
2.Delegation
如果使用 delegation 模式的話,發(fā)送者需要知道接收者奈辰,但是反過來沒有要求栏妖。
使用場景:
- 如果只要在相對(duì)接近的兩個(gè)模塊間傳遞消息,delegation 是很靈活很直接的消息傳遞機(jī)制奖恰。
3.KVO
KVO 是提供對(duì)象屬性被改變時(shí)的通知的機(jī)制底哥。
使用場景:
- 如果只對(duì)某個(gè)對(duì)象的值的改變感興趣的話,就可以使用 KVO 消息傳遞房官。
使用前提:
- 1.接收者(接收對(duì)象改變的通知的對(duì)象)需要知道發(fā)送者 (值會(huì)改變的對(duì)象)趾徽。
- 2.接收者需要知道發(fā)送者的生命周期,因?yàn)樗枰诎l(fā)送者被銷毀前注銷觀察者身份翰守。
4.Block
使用場景:
- 如果一個(gè)被調(diào)用的方法需要發(fā)送一個(gè)一次性的消息作為回復(fù)孵奶,那么使用 block 是很好的選擇。
- 如果要將處理的消息和對(duì)消息的調(diào)用放在一起來增強(qiáng)可讀性的話蜡峰,也可以使用 block了袁。
注意:為了不出問題,我們需要保證編碼器對(duì)象在某個(gè)時(shí)間點(diǎn)會(huì)釋放對(duì) block 的引用湿颅。
一旦任務(wù)完成载绿,completion block 調(diào)用過了以后,我們就應(yīng)該把它設(shè)為 nil油航。
5.Target-Action
Target-Action 消息的接收者不知道消息的發(fā)送者崭庸,并且消息的發(fā)送者也不知道消息的接收者。
使用場景:
- Target-action 機(jī)制非常適合響應(yīng) UI 的事件谊囚,沒有其他的消息傳遞機(jī)制能夠提供相同的功能怕享。
注意:如果 target 是明確指定的,那么 action 消息會(huì)發(fā)送給指定的對(duì)象镰踏。
如果 target 是 nil函筋, action 消息會(huì)一直在響應(yīng)鏈中被傳遞下去,直到找到一個(gè)能處理它的對(duì)象奠伪。
四跌帐、weak singleton 及使用場景
weak singleton 實(shí)現(xiàn)如下:
@implementation WeakSingleton
+ (instancetype)sharedInstance{
static __weak WeakSingleton *instance;
WeakSingleton *strongInstance = instance;
@synchronized (self) {
if (strongInstance == nil) {
strongInstance = [[[self class] alloc] init];
instance = strongInstance;
}
}
return strongInstance;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
static __weak WeakSingleton *instance;
WeakSingleton *strongInstance = instance;
@synchronized (self) {
if (strongInstance == nil) {
strongInstance = [super allocWithZone:zone];
instance = strongInstance;
}
}
return strongInstance;
}
- (id)copyWithZone:(NSZone *)zone{
return [WeakSingleton sharedInstance];
}
- (void)dealloc{
NSLog(@"-->> %s", __FUNCTION__);
}
@end
使用場景:
weak singleton 能在不同的地方訪問同一個(gè)對(duì)象首懈,如下圖: