一,单例模式:通过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:@"books.@avg.price"]; 求平均值
NSNumber *sumNumber = [p valueForKeyPath:@"books.@sum.price"];//求和
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 = @[@"