设计模式
设计模式是用来解决编程某些特写问题.
单例模式
什么时候使用单例模式?
在一个工程中,有一些类只需要一个实例变量.我们就可以将这些类设计成单例模式.
单例模式的作用?
当一个类 A
被设计成单例模式时,由 A
构造出的实例对象相比于其它类来讲,其为全局实例对象.即在每一个类中由 A
构造出的实例对象,都为相同对象.
在OC中如何将一个类设计成单例模式?
1.在要被设计成单例的类的 .h
文件中声明一个构造单例方法,如:
+(Student *)defaultIntance;
//命名可以是 shareIntance,
//也可以是 singleInstance
2.实现该方法
+(Student *)defaultIntance{
static Student *st = nil;//声明一个静态实例对象
if (st == nil) {
st = [[Student alloc] init];
}
return st;
}
//为了防止通过 alloc 或 new 创建新的实例对象
+(id)allocWithZone:(struct _NSZone *)zone{
@synchronized(self){
if (st == nil) {
st = [[super allocWithZone:zone ] init];
}
}
return st;
}
//为了防止 copy 产生出新的对象,需要实现NSCopying协议
-(id)copyWithZone:(NSZone *)zone{
return self;
}
观察者模式
什么是观察者模式?
在工程中,一些类去观察 A类
,当 A类
发生变化时,这些观察类就会收到消息,做出相应反应.
什么时候使用观察者模式?
当一个类需要发送消息给多个类的时候,就用观察者模式.
观察者模式的作用?
一对多的发送消息
如何在OC中实现观察者模式?
OC中观察者模式的设计基础: KVC / KVO
KVC的由来:在ios2.0之前,并没有属性来访问类中的实例变量,那时候开发人员使用 键值编码
的方式来访问类中的实例变量,即 KVC
方式.
Student *st = [[Student alloc] init];
[st setValue:@"yanshuxin" forKey:@"_name"];
[st setValue:[NSNumber numberWithInteger:21] forKey:@"_age"];
NSLog(@"des = %@",[st description]);
//访问
NSString *name = [st valueForKey:@"_name"];
NSNumber *age = [st valueForKey:@"_age"];
NSLog(@"name = %@,age = %ld",name,age);
//键路径编码
Book *book = [Book new];
// st.book = book;
// st.book.bookName = @"海贼王";
[st setValue:book forKeyPath:@"_book"];
[st setValue:@"海贼王" forKeyPath:@"_book._bookName"];
NSLog(@"%@",[book description]);
NSString *string = [st valueForKeyPath:@"_book._bookName"];
KVO的由来:在编程过程中,我们经常需要判断目标是否发生改变,以便及时的做出对应的处理.此时苹果公司就提供一种策略,即 OC运行时
提供了 KVO
技术.
KVO的实现:
1.注册成为观察者
-(id)initWithStudent:(Student *)s{
if (self = [super init]) {
self.s = s;
[self.s addObserver:self forKeyPath:@"_age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
}
return self;
}
2.观察者定义KVO回调
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
NSLog(@"change = %@",change);
if ([change[@"new"] integerValue] <=18 ) {
NSLog(@"不能小于18周岁.");
}
}
3.移除观察者
-(void)dealloc{
NSLog(@"End");
[self.s removeObserver:self forKeyPath:@"_age" context:nil];
}
代码示例:
#import "ViewController.h"
#import "Student.h"
#import "Monitor.h"
@interface ViewController ()
{
Student *s;
Monitor *m;
Hero *hero;
Sup *sup;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
s = [[Student alloc]init];
[s setValue:[NSNumber numberWithInteger:21] forKey:@"_age"];
m = [[Monitor alloc] initWithStudent:s];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(reduce:) userInfo:nil repeats:YES];
}
-(void)reduce:(NSTimer *)sender{
NSInteger age1 = [[s valueForKey:@"_age"] integerValue];
age1 -= 1;
if (age1 <= 18) {
[sender invalidate];
}
[s setValue:[NSNumber numberWithInteger:age1] forKey:@"_age"];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
通知
通过学习 KVO
,我们发现 KVO
就是一种简单的观察者模式,涉及到两个对象,分别是观察者和被观察者.这种方式实质上有很大局限生,那么OC的 Foundation
框架又为开发者们提供了新的一种观察者设计模式,即 通知
.
通知是一种发送给一个或者多个观察者,用来通知其在程序中发生了某个事件的消息.Cocoa中的通知机制遵循的是一种广播的模式.它是一种程序中事件的发起者或者是处理者和其他想要知道该事件的对象沟通的一种方式.
//初始化一个NSNotification类的实例对象
NSNotification *notification1 = [NSNotification notificationWithName:@"MESSAGE" object:nil ];
NSNotification *notification2 = [NSNotification notificationWithName:@"MESSAGE" object:self userInfo:@{@"content",@"xxx"}];
其中:
1.name:表示通知名称,最好英文名,用来识别通知对象
2.object:表示通知的发起人
3.userInfo:表示通知的内容
在现实生活中,我们的邮件都需要由邮局发送给接收人.在OC中也一样, Foundation
框架定义了一个单例类,通知中心 NSNotificationCenter
来统一发送通知的实例对象给观察者.
通知中心发送通知:
[[NSNotificationCenter defaultCenter] postNotification:notification1];
建立通知发送机制,步骤如下:
1.注册相关监听者,并实现监听收到通知的方法.
-(void)sendMessage{
[[NSNotificationCenter defaultCenter] postNotificationName:MESSAGE object:self userInfo:@{@"order":@"国王万岁"}];
}
-(void)doAction:(NSNotification *)notif{
NSDictionary *dic = [notif userInfo];
NSLog(@"工人们:%@",[dic objectForKey:@"order"]);
}
2.在需要的时候,被监听的对象去通知中心发送通知.
-(id)init{
if (self = [super init]) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doAction:) name:MESSAGE object:nil];
}
return self;
}
3.在 dealloc
方法中移除通知.
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:MESSAGE object:nil];
}
委托模式
两个对象间不能够直接联系,需要通过一个第三方对象,帮助他们联系,这样一种模式,我们称之为委托模式.
如何在OC中使用委托模式?在OC中实现委托模式需要了解OC中的一个元素 protocol
,即协议.
协议
协议是一套标准,定义了应该实现什么,但不关心具体怎么实现.
在OC中的协议是由 protocol
声明的一组方法列表.