一,單例模式:通過static關鍵詞,聲明全局變量。在整個進程運行期間只會被賦值一次。
/**
static : 修飾變量
1> 修飾全局變量
* 全局變量的作用域僅限於當前文件內部(不加的話別人使用extern關鍵字就能從其他文件訪問這個文件的全局變量了)
2> 修飾局部變量 :
* 能保證局部變量永遠只初始化1次,在程序運行過程中,永遠只有1分內存
* 局部變量的生命週期跟全局變量類似
* 但是不能改變作用域
*/
#pragma mark 懶漢式單例 arc
#import "HMMusicTool.h"
@implementation HMMusicTool
static id _instance; //保證這個全局變量只能當前文件可以訪問
/**
* alloc方法內部會調用這個方法
*/
+ (id)allocWithZone:(struct _NSZone *)zone
{
if (_instance ==nil) { //防止頻繁加鎖
@synchronized(self) {
if (_instance ==nil) { //防止創建多次
_instance = [super allocWithZone:zone];
}
}
}
return _instance;
}
+ (instancetype)sharedMusicTool
{
if (_instance ==nil) { //防止頻繁加鎖
@synchronized(self) {
if (_instance ==nil) { //防止多次init
_instance = [[self alloc] init];
}
}
}
return _instance;
}
//copy方法內部會調用這個方法
- (id)copyWithZone:(NSZone *)zone
{
return _instance;//保證copy方法調用之後也是這一個對象不會產生新的對象,因爲copy可能拷貝產生新的對象
}
@end
//// 餓漢式 (不需要掌握)
//#import "HMSoundTool.h"
//@implementation HMSoundTool
//
//static id _instance;
//
///**
// * 當類加載到OC運行時環境中(內存),就會調用一次(一個類只會加載1次)
// */
//+ (void)load
//{
// _instance = [[self alloc] init];
//}
//
//+ (id)allocWithZone:(struct _NSZone *)zone
//{
// if (_instance == nil) { // 防止其他創建多次
// _instance = [super allocWithZone:zone];
// }
// return _instance;
//}
//
//+ (instancetype)sharedSoundTool
//{
// return _instance;
//}
//
//- (id)copyWithZone:(NSZone *)zone
//{
// return _instance;
//}
//
/////**
//// * 當第一次使用這個類的時候纔會調用 (如果使用這個類的方法還需要調用父類的這個方法,比如繼承,那麼弗雷德initialize方法也會調用)和load的區別就在這
//// */
////+ (void)initialize
////{
//// NSLog(@"HMSoundTool---initialize");
////}
//@end
#pragma mark GCD模式單例 arc
#import <Foundation/Foundation.h>
@interface HMDataTool : NSObject
+ (instancetype)sharedDataTool;
@end
#import "HMDataTool.h"
@implementation HMDataTool
// 用來保存唯一的單例對象
static id _instace;
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [super allocWithZone:zone];
});
return _instace;
}
+ (instancetype)sharedDataTool
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [[self alloc] init];
});
return _instace;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instace;
}
@end
#pragma mark GCD單例模式非arc
#import "HMDataTool.h"
@implementation HMDataTool
// 用來保存唯一的單例對象
static id _instace;
+ (id)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [super allocWithZone:zone];
});
return _instace;
}
+ (instancetype)sharedDataTool
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [[self alloc] init];
});
return _instace;
}
- (id)copyWithZone:(NSZone *)zone
{
return _instace;
}
//非arc多了這幾個方法
- (onewayvoid)release{
}
- (id)retain {
returnself;
}
- (NSUInteger)retainCount {
return1;
}
- (id)autorelease {
returnself;
}
@end
#pragma mark 宏實現單例,自定義名稱,適配arc和非arc
創建一個HMSingleton.h文件,在.h文件中寫以下宏
// .h文件
#define HMSingletonH(name) + (instancetype)shared##name;
// .m文件
#if __has_feature(objc_arc)
#define HMSingletonM(name) \
static id _instace; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [super allocWithZone:zone]; \
}); \
return _instace; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [[self alloc] init]; \
}); \
return _instace; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return _instace; \
}
#else
#define HMSingletonM(name) \
static id _instace; \
\
+ (id)allocWithZone:(struct _NSZone *)zone \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [super allocWithZone:zone]; \
}); \
return _instace; \
} \
\
+ (instancetype)shared##name \
{ \
static dispatch_once_t onceToken; \
dispatch_once(&onceToken, ^{ \
_instace = [[self alloc] init]; \
}); \
return _instace; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return _instace; \
} \
\
- (oneway void)release { } \
- (id)retain { return self; } \
- (NSUInteger)retainCount { return 1;} \
- (id)autorelease { return self;}
#endif
再把HMSingleton.h文件導入pch文件即可
使用的時候就在需要使用的類的.h文件中加一句HMSingletonH .m文件加一句HMSingleton.m即可
二,觀察者模式:KVO是典型的通知模式,觀察某個屬性的狀態,狀態發生變化時通知觀察者。
//1.KVC
#pragma mark -KVC
- (void)viewDidLoad
{
[super viewDidLoad];
XLCustom * custom = [[XLCustom alloc]init];
//<1>
//原始方法對成員變量進行賦值使用的是setter方法或者點語法
//原始方法對成員變量進行獲取使用的是getter方法或者點語法
// custom.name = @"xuli";
// [custom setAge:19];
// NSLog(@"%@,%d",[custom name],custom.age);
//[結論]原始方法對成員變量進行賦值和獲取前提是該成員變量必須具有setter、getter方法的聲明和實現部分
//<2>KVC
//KVC 是key-value-coder的縮寫 鍵值編碼的簡稱
//KVC -------- 對象的屬性或者成員變量進行賦值進行賦值(私有的也可以修改),一般用來替換系統的私有的東西
/*
1、先去類中查找是否具有該變量的setter方法的聲明和實現部分 如果具有直接調用setter方法對成員變量進行賦值
2、如果不具有 繼續查找是否具有以該變量命名的成員變量 如果具有直接賦值
3、如果不具有 繼續查找是否具有以下劃線開頭以變量命名的成員變量 如果具有直接賦值 如果不具有崩潰
*/
//KVC 對成員變量進行賦值使用的方法是setValue:forkey(path): 前提是找到賦值的類的對象的指針
[custom setValue:@"xuli" forKey:@"name"];
[custom setValue:@(19) forKey:@"age"];
//KVC 對成員變量進行獲取使用的方法的是valueForkey(path):
NSLog(@"%@,%d",[custom valueForKey:@"name"],[[custom valueForKey:@"age"] intValue]);
//1.KeyPath和Key的區別
Person *p = [[Person alloc] init];
p.dog = [[Dog alloc] init];
p.dog.bone = [[Bone alloc] init];
// p.dog.bone.type = @"狗骨";
// [p setValue:@"豬骨" forKeyPath:@"dog.bone.type"];
// [p.dog setValue:@"豬骨" forKeyPath:@"bone.type"];
[p.dog.bone setValue:@"豬骨" forKeyPath:@"type"];
NSLog(@"%@", p.dog.bone.type);
// p.dog.name = @"wangwang";
// [p.dog setValue:@"wangcai" forKey:@"name"];
// [p.dog setValue:@"larry" forKeyPath:@"name"];
// [p setValue:@"hashiqi" forKeyPath:@"dog.name"];
//forKeyPath包含了forKey的功能,以後使用forKeyPath就可以了
//forKeyPath中可以利用.運算符, 就可以一層一層往下查找對象的屬性
// [p setValue:@"hashiqi" forKey:@"dog.name"]; // 寫法錯誤
// NSLog(@"%@", p.dog.name)
//2.關於KVC中的數據數組 (不常用,知道就好)
Person *p = [[Person alloc] init];
Book *book1 = [[Book alloc] init];
book1.name = @"5分鐘突破iOS開發";
book1.price = 10.5;
Book *book2 = [[Book alloc] init];
book2.name = @"5分鐘突破android開發";
book2.price = 18.5;
Book *book3 = [[Book alloc] init];
book3.name = @"5分鐘突破前端開發";
book3.price = 20.5;
Book *book4 = [[Book alloc] init];
book4.name = @"5分鐘突破PHP開發";
book4.price = 10.5;
p.books = @[book1, book2, book3, book4];
// 獲得所有的書名(將所有的書名放到一個數組中)
// NSMutableArray *names = [NSMutableArray array];
// for (Book *book in p.books) {
// [names addObject:book.name];
// }
// 取出books數組中每一個元素的name屬性值,放到一個新的數組中返回
NSArray *names = [p valueForKeyPath:@"books.name"];
[p valueForKeyPath:@"dog.name"];
NSLog(@"%@", names);
//取出數組中的books的價格,再把每一個價格加起來 返回值是NSNumber類型的數據
//NSNumber *avgNumber = [p valueForKeyPath:@"[email protected]"]; 求平均值
NSNumber *sumNumber = [p valueForKeyPath:@"[email protected]"];//求和
NSLog(@"%@", sumNumber);
// NSLog(@"%f", [sumNumber doubleValue]);
}
// 2. 使用KVC進行正向和反向傳值
//正向傳值:給下一個界面設一個屬性來接受傳過去的值,在這個界面獲取下一個界面的指針,用指針[next setValue:[UIColor magentaColor] forKey:@"nextColor"];
//反向傳值:在上一個界面設置一個屬性接受傳過來得值,在下一個界面設一個屬性id delegate; 設置下一個界面的屬性是上一個界面的指針.然後用代理(即上一個界面的指針)設置上一個界面的屬性值,這樣就反向傳過去了
// 3. KVO 的使用
#pragma mark - KVO
#import "XLViewController.h"
#import "XLBoy.h"
#import "XLGirl.h"
@interface XLViewController ()
{
XLBoy * boy;
XLGirl * girl;
}
@end
@implementation XLViewController
-(void)createUI
{
NSArray * array = @[@"