1.单例模式

2.观察者模式

3.委托代理

4.block回调

5.反射机制

6.多代理模式

单例模式

iOS单例模式的2种方式。根据线程安全的实现来区分,一种是使用@synchronized ,另一种是使用GCD的dispatch_once函数。

要实现单例,首先需要一个static的指向类本身的对象,其次需要一个初始化类函数。下面是两种实现的代码。

@synchronized

static InstanceClass *instance;
+ (InstanceClass *)shareInstance{
@synchronized (self){
if (instance == nil) {
instance = [[InstanceClass alloc] init];
}
}
return instance;
}

GCD

static InstanceClass *instance;
+ (InstanceClass *)shareInstance{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[InstanceClass alloc] init];
});
return instance;
}

示例:

+(MyClass *)shareInstance
{
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [[self alloc]init];
});
return instance;
}

观察者模式

Notification(通知)

//向通知中心添加消息监听名称,和通知方法
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(viewDisappear:) name:@"DismissFaceVerifyController" object:nil]; //通过通知中心调用对应消息名
[[NSNotificationCenter defaultCenter] postNotificationName:@"DismissFaceVerifyController" object:self userInfo:nil];

KVO(键值监听),即Key-Value Observing

监听对象的属性(成员变量)变化,对象可以是自己也可以是其它

//实例监听自己的属性

//ViewController.m文件

//
// ViewController.m
// KVOLearn
//
// Created by Vie on 2017/4/6.
// Copyright © 2017年 Vie. All rights reserved.
// #import "ViewController.h" @interface ViewController ()
@property(strong, nonatomic) NSString *testStr;
@end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; self.testStr=@"Tracer"; //按钮
UIButton *loginBtn=[[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width/-, , , )];
[loginBtn setTitle:@"改变值" forState:UIControlStateNormal];
[loginBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[loginBtn setBackgroundColor:[UIColor redColor]];
[loginBtn.layer setBorderWidth:0.2f];
[loginBtn.layer setCornerRadius:10.0f];
[loginBtn addTarget:self action:@selector(changeAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:loginBtn]; /*1.注册对象self为被观察者: option中,
forKeyPath为被观察的对象属性
NSKeyValueObservingOptionOld 以字典的形式提供 “初始对象数据”;
NSKeyValueObservingOptionNew 以字典的形式提供 “更新后新的数据”; */
[self addObserver:self forKeyPath:@"testStr" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
}
//按钮事件
-(void)changeAction:(UIButton *)sender{
self.testStr=@"Vie";
} /* 只要object的keyPath属性发生变化,就会调用此回调方法*/
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"testStr"]) {
NSLog(@"监听到testStr属性值改变");
}
}
-(void)dealloc{
//移除self中forKeyPath属性观察
[self removeObserver:self forKeyPath:@"testStr" context:nil];
} @end

委托代理

delegate

委托应用场景:一个view把一些业务交给 控制器去实现,然后控制器实现委托改变view

//在ViewController.h中声明协议如下

@protocol ByValueDelegate <NSObject>
-(void) passValue:(NSString *) value;
@end

//在ViewController.h中声明委托变量

@property (nonatomic,weak) id<ByValueDelegate> delegate;//声明一个委托变量 

//在ViewController.m中设置代理

UserinfoView *uiv=[[UserinfoView alloc]init];
//把值委托到UserinfoView.m的实现委托的方法里面
self.delegate=uiv;//设置该对象代理为对象uiv
[self.delegate passValue:@"委托传值跳转"];

//在UserinfoView.h中,引用ViewController的头文件,并添加代理协议如下

#import "ViewController.h" 

@interface UserinfoView : UIViewController<ByValueDelegate>@property (nonatomic,strong) UILabel *showLable;
@property (nonatomic,retain) UserinfoEntity *showUserinfoEntity;
-(void) viewDidLoad;@end

//在UserinfoView.m中实现代理函数

//实现委托方法
-(void) passValue:(NSString *)value{
UIAlertView *alterOk = [[UIAlertView alloc] initWithTitle:@"提示" message:value delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alterOk show];
}

KVC(键值编码),即Key-Value Coding,一个非正式的Protocol,使用字符串(键)访问一个对象实例变量的机制

就是指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。而不需要调用明确的存取方法。这样就可以在运行时动态在访问和修改对象的属性。而不是在编译时确定,这也是iOS开发中的黑魔法之一。

KVC在iOS中的定义

无论是Swift还是Objective-C,KVC的定义都是对NSObject的扩展来实现的(Objective-c中有个显式的NSKeyValueCoding类别名,而Swift没有,也不需要)所以对于所有继承了NSObject在类型,都能使用KVC(一些纯Swift类和结构体是不支持KVC的),下面是KVC最为重要的四个方法
//KVC最为重要的四个方法

- (nullable id)valueForKey:(NSString *)key;                          //直接通过Key来取值
- (void)setValue:(nullable id)value forKey:(NSString *)key; //通过Key来设值
- (nullable id)valueForKeyPath:(NSString *)keyPath; //通过KeyPath来取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; //通过KeyPath来设值

//例

//PersonInfoModel.h文件

//
// PersonInfoModel.h
// KVCLearn
// 个人信息
// Created by Vie on 2017/4/6.
// Copyright © 2017年 Vie. All rights reserved.
// #import <Foundation/Foundation.h> @interface PersonInfoModel : NSObject
@property(strong, nonatomic) NSString *name;//姓名
@property(strong, nonatomic) NSString *gender;//性别
@property(assign, nonatomic) NSNumber *age;//年龄
@end

//StudentInfoModel.h文件

//
// StudentInfoModel.h
// KVCLearn
// 学生信息
// Created by Vie on 2017/4/6.
// Copyright © 2017年 Vie. All rights reserved.
// #import <Foundation/Foundation.h>
#import "PersonInfoModel.h"
@interface StudentInfoModel : NSObject
@property(strong, nonatomic)PersonInfoModel *personModel;//个人信息
@property(strong, nonatomic)NSString *studentID;//学号
@property(strong, nonatomic)NSString *departments;//院系
@end

//使用

#import "StudentInfoModel.h"

 StudentInfoModel *studentModel=[[StudentInfoModel alloc] init];
//设值
[studentModel setValue:@"信息技术学院" forKey:@"departments"];
[studentModel setValue:@"Vie" forKeyPath:@"personModel.name"];
//取值
NSLog(@"%@",[studentModel valueForKey:@"departments"]);
NSLog(@"%@",[studentModel valueForKeyPath:@"departments"]);

修改系统控件内部属性(runtime + KVC)

将UIPageControl样式原来样式

修改为下面

PageControl公开属性没有直接可以修改的,目前可以自定义PageControl,这种方式看起来不简单。另一种方式就是,通过runtime遍历出UIPageControl所有属性(包括私有成员属性,runtime确实很强大)。

 //遍历属性
unsigned int count = ;
Ivar *ivars = class_copyIvarList([UIPageControl class], &count);
for (int i = ; i < count; i++) {
Ivar ivar = ivars[i];
//获取所有私有属性
const char *property = ivar_getName(ivar);
NSLog(@"%@",[[NSString alloc]initWithCString:property encoding:NSUTF8StringEncoding]);
}

//运行结果

-- ::20.756 KVCLearn[:] _lastUserInterfaceIdiom
-- ::20.756 KVCLearn[:] _indicators
-- ::20.757 KVCLearn[:] _currentPage
-- ::20.757 KVCLearn[:] _displayedPage
-- ::20.757 KVCLearn[:] _pageControlFlags
-- ::20.757 KVCLearn[:] _currentPageImage
-- ::20.757 KVCLearn[:] _pageImage
-- ::20.757 KVCLearn[:] _currentPageImages
-- ::20.758 KVCLearn[:] _pageImages
-- ::20.758 KVCLearn[:] _backgroundVisualEffectView
-- ::20.758 KVCLearn[:]_currentPageIndicatorTintColor
-- ::20.758 KVCLearn[:] _pageIndicatorTintColor
-- ::20.758 KVCLearn[:] _legibilitySettings
-- ::20.758 KVCLearn[:] _numberOfPages

//找到了属性后,接着实现

//然后通过KVC设置自定义图片,实现了效果,代码如下:
UIPageControl *pageControl = [[UIPageControl alloc] init];
[pageControl setValue:[UIImage imageNamed:@"home_slipt_nor"] forKeyPath:@"_pageImage"];
[pageControl setValue:[UIImage imageNamed:@"home_slipt_pre"] forKeyPath:@"_currentPageImage"];

block回调

block中使用修改方法外的属性需要用__block修饰,例如:

__block BOOL whoopsSomethingWrongHappened = true;

//ViewController.m文件
#import "ViewController.h"
#import "CallbackTest.h"
@interface ViewController () @end @implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor whiteColor]];
UIButton *backBtn=[[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width*0.4, self.view.frame.size.height*0.475, self.view.frame.size.width*0.2, self.view.frame.size.height*0.05)];
[backBtn.layer setCornerRadius:5.0];
[backBtn setTitle:@"回调" forState:UIControlStateNormal];
[backBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[backBtn.layer setBorderWidth:0.5];
[backBtn addTarget:self action:@selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:backBtn];
} /**
* @Author Vie, 2015-08-05 13:41:37
* 使用block回调函数
* @param sender sender description
*
* @since <#version number#>
*/
-(void)btnAction:(UIButton *)sender{
CallbackTest *backTest=[[CallbackTest alloc] init];
//第一种回调方式
// [backTest startString:@"回调开始" callBack:^(NSString *backFunstring) {
// 回调时候会执行
// UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"回调提示" message:backFunstring delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
// [alert show];
//
// }]; //第二种回调方式
backTest.backCall=^(NSString *string){
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:@"回调提示"message:string delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alert show];
};
[backTest blockCall:@"回调开始"];
}
@end
//CallbackTest.h文件

#import <UIKit/UIKit.h>
@interface CallbackTest : NSObject
//定义一个block,返回值为void,参数为NSString
typedef void(^backFunction)(NSString *backFunstring);
@property (nonatomic,copy) backFunction backCall;
-(void)startString:(NSString *)str callBack:(backFunction)backString;
-(void)blockCall:(NSString *)str;//第一一个block属性
@end
//CallbackTest.m文件
#import "CallbackTest.h"

@implementation CallbackTest
//第一种回调方式
-(void)startString:(NSString *)str callBack:(backFunction)backString{
NSMutableString *mutString=[str mutableCopy];
[mutString appendString:@"回调完成"];
//执行block
// backString(mtuString);
//将block回调交给另一个方法执行
[self TestBackCall:mutString callBack:backString];
} //执行block回调的函数
-(void)TestBackCall:(NSMutableString *)mutString callBack:(backFunction)testBack{
testBack(mutString);
} //第二种回调方式
-(void)blockCall:(NSString *)str{
NSMutableString *mutString=[str mutableCopy];
[mutString appendString:@"回调完成"];
_backCall(mutString);
}
@end

反射机制

//使用NSClassFromString,通过字符串获取类
Class class=NSClassFromString(@"UIAlertView");
//或者使用objc_getClass,通过字符串获取类
//Class class=objc_getClass("UIAlertView");
id alert= [[class alloc] initWithTitle:@"" message:@"" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alert show];

多代理模式

  使用NSPointerArray进行多代理可以跟踪内存,它是mutable,数组不会增加这个对象的引用计数

//例

//MoreDelegate.h文件

//
// MoreDelegate.h
// MoreDelegate
// 委托
// Created by Vie on 2017/5/2.
// Copyright © 2017年 Vie. All rights reserved.
//
@protocol MoreDelegate <NSObject> @optional
-(void)testMoreDelegate;//多代理测试 @end

//后面可以结合通知(或者其他方式)使用,到达方法准确调用带参。

//MoreDelegateManager.h文件

//
// MoreDelegateManager.h
// MoreDelegate
// 多代理管理实现类
// Created by Vie on 2017/5/2.
// Copyright © 2017年 Vie. All rights reserved.
// #import <Foundation/Foundation.h>
#import "MoreDelegate.h" @interface MoreDelegateManager : NSObject /**
单例模式 @return self
*/
+(MoreDelegateManager *)shareInstance; /**
注册代理 @param obj 需要实现代理的对象
*/
-(void)registerDelegate:(id)obj; /**
解除代理 @param obj 需要接触代理的对象
*/
-(void)unRegisterDelegate:(id)obj; /**
执行代理方法(后续可以多个方法提供出去,方便传参调用) @param aSelector 类方法选择器
*/
-(void)delegateAction:(SEL)aSelector;
@end

//MoreDelegateManager.m文件

//
// MoreDelegateManager.m
// MoreDelegate
//
// Created by Vie on 2017/5/2.
// Copyright © 2017年 Vie. All rights reserved.
// #import "MoreDelegateManager.h" #import <objc/runtime.h>
#import <objc/message.h> @interface MoreDelegateManager ()<MoreDelegate>
@property(nonatomic,strong) NSPointerArray *delegateArr;//实现委托的数组
@end @implementation MoreDelegateManager
#pragma mark 懒加载
-(NSPointerArray *)delegateArr{
if (!_delegateArr) {
_delegateArr=[NSPointerArray weakObjectsPointerArray];
}
return _delegateArr;
} #pragma mark 对外方法
/**
单例模式 @return self
*/
+(MoreDelegateManager *)shareInstance{
static id instanc;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instanc=[[self alloc] init];
});
return instanc;
}
/**
注册代理 @param obj 需要实现代理的对象
*/
-(void)registerDelegate:(id)obj{
NSLog(@"注册代理类:%@",NSStringFromClass([obj class].class));
[self.delegateArr addPointer:(__bridge void*)obj];
} /**
解除代理 @param obj 需要接触代理的对象
*/
-(void)unRegisterDelegate:(id)obj{
NSLog(@"解除注册代理类:%@",NSStringFromClass([obj class].class));
NSUInteger index=[self indexOfDelegte:obj];
if (index!=NSNotFound) {
[self.delegateArr removePointerAtIndex:index];
}
//去掉数组里面的野指针
[self.delegateArr compact];
} /**
执行代理方法 @param aSelector 类方法选择器
*/
-(void)delegateAction:(SEL)aSelector{
for (id delegate in self.delegateArr) {
if (delegate&&[delegate respondsToSelector:aSelector]) {
// ((void (*) (id, SEL)) objc_msgSend) (delegate, aSelector);
[delegate testMoreDelegate];
}
}
} #pragma mark 内部使用方法 /**
计算Delegate的下标 @param obj 代理委托类
@return 下标
*/
-(NSUInteger)indexOfDelegte:(id)obj{
for (NSUInteger i=; i<self.delegateArr.count; i++) {
if ([_delegateArr pointerAtIndex:i]==(__bridge void*)obj) {
return i;
}
}
return NSNotFound;
}
@end

//使用

//在几个不同的控制器中注册代理
[[MoreDelegateManager shareInstance] registerDelegate:self]; //调用事件
[[MoreDelegateManager shareInstance] delegateAction:@selector(testMoreDelegate)]; //实现委托方法
-(void)testMoreDelegate{
NSLog(@"代理实现类:%@",NSStringFromClass(self.class));
}

iOS,几种设计模式的更多相关文章

  1. iOS 23 种设计模式

    设计模式主要分三个类型:创建型.结构型和行为型. 其中创建型有: 一.Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点 二.Abstract Factory,抽象工厂 ...

  2. iOS 开发之 23种设计模式

    整理了 iOS 开发中用到的设计模式: iOS 开发之 设计模式[一]原型模式 (Prototype pattern) iOS 开发之 设计模式[二]工厂方法模式 iOS 开发之 设计模式[三]抽象工 ...

  3. iOS 趣谈设计模式——通知

    [前言介绍] iOS的一种设计模式,观察者Observer模式(也叫发布/订阅,即Publich/Subscribe模式). 观察者模式,包含了通知机制(notification)和KVO(Key-v ...

  4. IOS开发常用设计模式

    IOS开发常用设计模式 说起设计模式,感觉自己把握不了笔头,所以单拿出iOS开发中的几种常用设计模式谈一下. 单例模式(Singleton) 概念:整个应用或系统只能有该类的一个实例 在iOS开发我们 ...

  5. iOS常用的设计模式

    iOS常用的设计模式有:单例模式.委托模式.观察者模式和MVC模式.下面分别简单介绍. 一:单例模式 我们常用的UIApplication.NSUserdefaults.NSNotificationC ...

  6. Flyweight模式_Java中23种设计模式

    —————————— ASP.Net+Android+IOS开发..Net培训.期待与您交流! —————————— 享元模式: Flyweight模式的有效性很大程度上取决于如何使用它以及在何处使用 ...

  7. iOS单例设计模式具体解说(单例设计模式不断完好的过程)

    在iOS中有非常多的设计模式,有一本书<Elements of Reusable Object-Oriented Software>(中文名字为<设计模式>)讲述了23种软件设 ...

  8. Java开发中的23种设计模式详解

    [放弃了原文访问者模式的Demo,自己写了一个新使用场景的Demo,加上了自己的理解] [源码地址:https://github.com/leon66666/DesignPattern] 一.设计模式 ...

  9. Java开发中的23种设计模式详解(转)

    设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...

随机推荐

  1. 对JavaScript中异步同步机制以及线程深入了解

    今天在网上看到各种对Js异步同步单线程多线程的讨论 经过前辈们的洗礼 加上鄙人小小的理解 就来纸上谈兵一下吧~ Js本身就是单线程的 至于为什么Js是单线程的 那就要追溯到Js的历史了 总而言之 由于 ...

  2. asp.net c# 网上搜集面试题目大全(附答案)

    1.String str=new String("a")和String str = "a"有什么区别? String str = "a"; ...

  3. 弹性盒子布局flexbox

    弹性盒子display:flexbox一般应用于父元素的容器上,然后对子元素来进行弹性布局 设置了flexbox的父元素不能设置具体的宽度与高度的值,而是通过子元素来设置值,父元素弹性的包裹既可 相关 ...

  4. 2016-2017 ACM-ICPC, NEERC, Northern Subregional Contest

    A. Anniversary Cake 随便挑两个点切掉就好了. #include<bits/stdc++.h> using namespace std; const int Maxn=2 ...

  5. [BZOJ3874][AHOI2014] 宅男计划

    Description 外卖店一共有N种食物,分别有1到N编号.第i种食物有固定的价钱Pi和保质期Si.第i种食物会在Si天后过期.JYY是不会吃过期食物的.比如JYY如果今天点了一份保质期为1天的食 ...

  6. HDU 3308 LCIS(线段树)

    题目链接 模板题吧,忘了好多,终于A了... #include <cstring> #include <cstdio> #include <string> #inc ...

  7. 【Linux】unzip命令,记一次遇到的问题

    最近在做BOSS系统云平台部署脚本,联调时发现Shell脚本中存在问题,下方记录 某个地方提示是否覆盖 [root@haiwai test]# unzip /home/redis/test/main- ...

  8. <六>JDBC_DAO 设计模式

    JDBC_DAO设计模式 DAO:Data Access Object(数据访问对象)  why:实现功能的模块化,更有利于代码的维护和升级.  what:访问数据信息的类,包含了对数据的CRUD(c ...

  9. initWithCoder: 与initWithFrame:的区别

    从nib中加载对象实例时,init:或initWithFrame:都不会调用.而是调用initWithCoder:怎么理解:   有时候,知道initWithFrame方法如何用,但是么有弄明白ini ...

  10. 解决scrollview上的menu拖动问题以及menu item在可视区外仍能触发的问题

    最近在做项目发现一个让人很头疼的问题 qiick-3.5 引擎 lua 版本 一 问题如下: ① 在Cocostudio中做界面 使用 scrollview 控件 ,然后 scrollview 控件的 ...