iOS有哪些常见的设计模式?
单例模式/委托模式/观察者模式/MVC模式
单例模式
单例保证了应用程序的生命周期内仅有一个该类的实例对象,而且易于外界访问.
在ios sdk中,UIApplication, NSBundle, NSNotificationCenter, NSFileManager, NSUserDefault, NSURLCache等都是单例.
在实际开发中,单例一般会分为ARC和非ARC两种不同的写法,这些代码可以通过判断统一整理到PCH文件中,这样每次使用单例时就不用多次输入重复的代码.
单例的代码简单样例:
//.h
@interface Singleton:NSObject
+(Singleton *)sharedManager;
@property(nonatomic,strong)NSString *singletonData;
@end
//.m
#import "Singleton.h"
@implementation Singleton
static Singleton *sharedManager = nil;
+(Singleton *)sharedManager
{
static dispatch_once_t once;
dispatch_once(&once,^{
sharedManager = [[self alloc] init];
});
return sharedManager;
}
@end
委托模式
委托Delegate是协议的一种,通过@protocol方式实现. 顾名思义, 就是委托他人帮自己去做什么事. 也就是当自己不方便做什么事情的时候, 就可以建立一个委托, 这样就可以委托他人帮忙去做.
比如常见的UITableView, iOS SDK在写这个类的时候,肯定不知道开发者想要在点击某一行之后都要进行什么操作, 所以只好让程序员委托UIViewController去代理UITableViewDelegate来实现这个方法.
同样的,它也不知道开发者希望这个表有多少行,每个cell的内容都是什么样的,所以UITableView只好委托UIViewController去代理他的UITableViewDataSource来实现这些方法.
当然,代理方法一是可以传递事件, 二也可以用来传递值,
比如:tableview的datasource里的一个代理方法
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
委托者可以把行数通过indexpath传递给被委托者,被委托者取到行数之后,自定义如何表现这个cell,再把cell传回给委托者.
下面有用一个Man类的例子来详细解说一下.
Man类,可以初始化一个胖子或瘦子,然后完成他的早中晚的一天......然后吃饭工作睡觉之后都干什么他自己不知道.....只好告诉你他吃了什么,睡了多久 ,让你来帮他决定.....我瞎编的...你也许可以编一个好一点的....
//man.h
#import <Foundation/Foundation.h>
//*************** delegate ***********************
//创建代理.吃喝工作的结果让别人帮你完成,你只需要提供吃了啥,睡了多久就行了.
@protocol ManDelegate <NSObject>
@required
//人可以吃不睡,但是一定要工作啊....所以required
-(void)work;
@optional
//返回一个睡觉的时间给被委托的对象,通过这个时间来处理相关事宜
-(void)sleepWithTime:(int)time;
//通过给被委托者一种食物,返回一个布尔值,来判断是否吃饱.
-(BOOL)eatWithFood:(NSString *)food;
@end
//*************** delegate ***********************
@interface Man : NSObject
//delegate属性
@property (nonatomic, weak) id<ManDelegate> delegate;
//是胖,是瘦呢,这个在实例化类的时候完成.
@property (nonatomic, assign) BOOL isFat;
//你这一天都分别干了啥,这个要你自己完成
-(void)morning;
-(void)afternoon;
-(void)everning;
@end
//man.m
#import "Man.h"
@implementation Man
//通过[self.delegate XXXX]确定代理出去的方法在自己的方法里的实现的位置;
//早上睡了7个小时.吃了点面包,没吃饱就不工作,吃饱了就接着工作..
-(void)morning{
[self.delegate sleepWithTime:7];
BOOL isFull = [self.delegate eatWithFood:@"面包"];
//觉得面包吃饱了就工作,面包吃不饱就不工作.
if(isFull == YES){
NSLog(@"早饭吃饱了,工作");
[self.delegate work];
}
else{
NSLog(@"早饭吃饱了,不工作");
}
}
//中午睡了1个小时,睡完接着工作.
-(void)afternoon{
[self.delegate sleepWithTime:1];
[self.delegate work];
}
//晚上睡了3个小时...
-(void)everning{
[self.delegate sleepWithTime:3];
}
@end
//代理执行的位置
#import "ViewController.h"
#import "Man.h"
@interface ViewController ()<ManDelegate>
@property (nonatomic,retain) Man *zhangsan;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//初始化一个张三实例,张三不胖.
self.zhangsan = [[Man alloc] init];
self.zhangsan.isFat = NO;
//把张三工作/吃/睡之后要干嘛,交给self也就是ViewController来决定,就是实现代理方法
self.zhangsan.delegate = self;
//张三的一天.
[self.zhangsan morning];
[self.zhangsan afternoon];
[self.zhangsan everning];
}
#pragma mark ----ManDelegate
//viewcontroller决定,让张三工作的时候打印一句话到控制台.
-(void)work{
NSLog(@"Working");
}
//viewcontroller决定,根据张三提供来的休息时间,把他的休息情况打印到控制台上.
-(void)sleepWithTime:(int)time
{
NSLog(@"Slept for %d hour",time);
if(time>4){
NSLog(@"长眠不起");
}else if(time == 4){
NSLog(@"不长不短");
}else if(time < 4){
NSLog(@"小眯一下");
}
}
//viewcontroller决定,通过张三提供吃的食物的内容,来判断张三是不是吃饱了...并且返回给张三...让他自己通过判断自己饱了没饱来处理一些事情
-(BOOL)eatWithFood:(NSString *)food{
if (self.zhangsan.isFat == YES && [food isEqualToString:@"面包"]) {
return NO;
}
else if(self.zhangsan.isFat == NO && [food isEqualToString:@"面包"]){
return YES;
}
else{
return YES;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
问题1:为什么delegate作为属性需要是weak?
防止retain cycle循环引用...
比如tableview....UIViewCotroller通过self.view addsubview.已经指向tableview了......所以tableview.delegate = self 和tableview.datasource又指向了viewcontroller,如果此时delegate是strong,就会发生循环引用无法释放,所以这里应该是weak.....详细见上一章属详解.
观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。 简而言之,就是A和B,A对B的变化感兴趣,就注册为B的观察者,当B发生变化时通知A,告知B发生了变化。这个也叫做经典观察者模式。
在iOS中,观察者模式的具体实现有两种: 通知机制(notification)和KVO机制(Key-value Observing)
1.通知机制
注册通知接收者的代码:
[[NSNotificationCenter DefaultCenter] addObserver:self
selector:@selector(registerCompeletion:)
name:@"RigsterCompletionNotification"
object:nil];
-(void)registerCompletion:(NSNotification *)notification{
NSDictionary *theData = [notification useInfo];
NSString *username = [theData objectForKey:@"username"];
NSLog(@"username = %@",username);
}
投送通知的代码
NSDictionary *dataDic = [NSDictionary dictionaryWithObject:self.text
forkey:@"username"];
[[NSNotificationCenter DefaultCenter] postNotificationName:@"RegisterCompeletionNotification"
object:nil
userInfo:dataDict];
问题1. object是干嘛的?是不是可以用来传值?
答:object是用来过滤Notification的,只接收指定的sender所发的Notification.....传值请用userInfo,而不是object
问题2. iOS中,广播通知(broadcast notification)/本地通知(local notification)/推送通知(push notification)有什么区别和不同?
出了名字相似以外,广播通知和其他两个通知是完全不一样的: 广播通知是cocoatouch中观察者模式的一种机制, 实现应用内部多个对象的通信...本地通知和推送通知中的"通知"是一种"提示"...通过警告框,发出声音,振动和在应用图标上显示数组等,在计划时间到达时,本地通知通过本地iOS发出,推送通知由第三方程序发送给苹果远程服务器,再由远程服务器推送给iOS特定应用.
2.KVO机制
对象的属性变化时,通知会直接发送到观察者对象.
可以用来实现 ,比如, UITableView滑动时导航自动变换颜色,或者,一个计算房贷的软件,当首付金额改变时,每月还款数目等数据相应自动改变等.
这里来观察UITableView一个实例的contentOffset属性.
//添加监听者
[self.tableView addObserver:self //监听者
forKeyPath:@"contentOffset" //被观察对象的属性字符串
options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld//设置.这里的设置表示把属性变换的新旧两个值都传递给观察者
context:nil];//上下文内容,c语言形式的任何指针类型
//监听属性变化时的回调
-(void)obserValueForKeyPath:(NSString *)keyPath //被观察的属性
ofObject:(id)object //被观察的对象
change:(NSDictionary *)change//字典类型包含了变化的内容,与options呼应
context:(void *)context//传递过来的上下文
{
NSLog(@"%@-%@",keyPah, (NSString *)change[NSKeyValueChangeNewKey]);//通过change字典渠道变化的属性变化前或变化后的值.
}
网友评论