OC 设计模式
设计模式
一种或几种被所有程序员广泛认同的,有某些特定功能,或者实现某些特殊作用的编码格式
单例模式
键值编码(KVC)
键值观察(KVO)
观察者模式()
工厂模式(工厂方法)
ps:MVC && MVVM && CVC
一、单例模式
#import <Foundation/Foundation.h> /*
单例模式
1.通常情况下,一个工程只有一个单例类。
2.我们将一个类选中,将它作为单例类。
3.在整个工程中这个类所创建的对象是唯一并且不能被释放 作用:界面传值-在整个工程任意位置对单例对象的属性进行赋值
也可以在整个工程的任意位置对单例对象的属性进行访问
*/
@interface Globle : NSObject @property (strong, nonatomic) NSString *userId; // 单例方法
// 作用:获取唯一单例对象
+ (Globle*) shareGloble;//getGloble @end #import "Globle.h" // 创建一个单例对象,用静态修饰符将这个对象的生命周期延长至整个工程
static Globle *globle = nil; @implementation Globle +(Globle *)shareGloble
{
// 第一次执行单例方法,将单例对象初始化
if (globle == nil) {
globle = [[Globle alloc] init];
globle.userId = @"";
}
// 之后的每次调用,都会直接返回上面的唯一单例对象
return globle;
}
@end #import <Foundation/Foundation.h>
#import "Globle.h" @interface People : NSObject +(void) showUserId; @end #import "People.h" @implementation People +(void)showUserId
{
NSLog(@"userId:%@",[Globle shareGloble].userId);
}
@end #import <Foundation/Foundation.h>
#import "Globle.h"
#import "People.h" int main(int argc, const char * argv[]) {
@autoreleasepool { [Globle shareGloble].userId = @"";
[People showUserId]; }
return ;
}
二、KVC
#import <Foundation/Foundation.h> /*
KVC key-value-coding 作用:能够无视OC中关于私有的设定,直接通过底层赋值方式对属性赋值(和获取); */
@interface KVCClass : NSObject -(void) showProperty; @end #import "KVCClass.h"
#import "Student.h" @interface KVCClass () @property (strong, nonatomic) NSString *kvcProperty;
@property (strong, nonatomic) Student *tempStu; @end @implementation KVCClass - (instancetype)init
{
self = [super init];
if (self) {
self.tempStu =[[Student alloc] init];
}
return self;
} -(void)showProperty
{
NSLog(@"property:%@",self.kvcProperty);
NSLog(@"property:%@",self.tempStu.name); }
@end #import <Foundation/Foundation.h> @interface Student : NSObject @property (strong, nonatomic) NSString *name; @end #import "Student.h" @implementation Student @end #import <Foundation/Foundation.h> #import "KVCClass.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
KVCClass *kvc = [[KVCClass alloc] init]; //表示 在KVC对象中查找名字为[kvcProperty] 的属性,并对这个属性赋值为@“bowen”
// 设置
[kvc setValue:@"bowen" forKey:@"kvcProperty"]; [kvc setValue:@"bowen1" forKeyPath:@"tempStu.name"]; [kvc showProperty];
// 取值
NSLog(@"%@",[kvc valueForKey:@"kvcProperty"]);
NSLog(@"%@",[kvc valueForKeyPath:@"tempStu.name"]);
}
return ;
}
OC中的KVC操作就和Java中使用反射机制去访问类的private权限的变量,很暴力的,这样做就会破坏类的封装性,本来类中的的private权限就是不希望外界去访问的,但是我们这样去操作,就会反其道而行,但是我们有时候真的需要去这样做,哎。所以说有些事不是都是顺其自然的,而是需要的时候自然就诞生了。
下面就来看一下这种技术的使用:
Dog.h
- //
- // Dog.h
- // 42_KVC
- //
- // Created by jiangwei on 14-10-14.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- @interface Dog : NSObject
- @end
Dog.m
- //
- // Dog.m
- // 42_KVC
- //
- // Created by jiangwei on 14-10-14.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import "Dog.h"
- @implementation Dog
- @end
定义了Dog这个类,但是什么都没有,他只是一个中间类,没什么作用,在这个demo中。
Person.h
- //
- // Person.h
- // 42_KVC
- //
- // Created by jiangwei on 14-10-14.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import "Dog.h"
- @interface Person : NSObject{
- @private
- NSString *_name;
- NSDog *_dog;
- NSInteger *age;
- }
- @end
Person.m
- //
- // Person.m
- // 42_KVC
- //
- // Created by jiangwei on 14-10-14.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import "Person.h"
- @implementation Person
- - (NSString *)description{
- NSLog(@"%@",_name);
- return _name;
- }
- @end
Person类中我们定义了两个属性,但是这两个属性对外是不可访问的,而且也没有对应的get/set方法。我们也实现了description方法,用于打印结果
看一下测试代码
main.m
- //
- // main.m
- // 42_KVC
- //
- // Created by jiangwei on 14-10-14.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import "Person.h"
- #import "Dog.h"
- //KVC:很暴力,及时一个类的属性是私有的,而且也没有get/set方法,同样可以读写
- //相当于Java中的反射,破坏类的封装性
- int main(int argc, const charchar * argv[]) {
- @autoreleasepool {
- Person *p = [[Person alloc] init];
- //设置值
- //这里setValue方法:第一个参数是value,第二个参数是key(就是类的属性名称)
- [p setValue:@"jiangwei" forKey:@"name"];
- Dog *dog = [[Dog alloc] init];
- [p setValue:dog forKey:@"dog"];
- //KVC设置值时,如果属性有set方法,则优先调用set方法,如果没有则直接设置上去,get方法类似
- //读取值
- NSString *name = [p valueForKey:@"name"];
- //设置基本数据类型
- //这里需要将基本类型转化成NSNumber
- //在设置值的时候,会有自动解包的过程,NSNumber会解包赋值给age
- [p setValue:@22 forKey:@"age"];
- NSLog(@"%@",p);
- return 0;
- }
- return 0;
- }
这里我们生成一个Person对象,然后开始使用KVC技术了:
1、设置属性值
- //设置值
- //这里setValue方法:第一个参数是value,第二个参数是key(就是类的属性名称)
- [p setValue:@"jiangwei" forKey:@"name"];
- Dog *dog = [[Dog alloc] init];
- [p setValue:dog forKey:@"dog"];
使用setValue方法,就可以进行对属性进行设置值操作了,同时需要传递这个属性的名称,这个和Java中使用反射机制真的很像。
注:KVC设置值时,如果属性有set方法,则优先调用set方法,如果没有则直接设置上去,get方法一样
- //设置基本数据类型
- //这里需要将基本类型转化成NSNumber
- //在设置值的时候,会有自动解包的过程,NSNumber会解包赋值给age
- [p setValue:@22 forKey:@"age"];
还有一个需要注意的地方:当我们在设置基本类型的时候,需要将其转化成NSNumber类型的。
2、取属性的值
- //读取值
- NSString *name = [p valueForKey:@"name"];
取值就简单了
下面再来看一下KVC中强大的功能:键值路径
键值路径是对于一个类中有数组对象的属性进行便捷操作。
看个场景:
一个作者有多本书
Author.h
- //
- // Author.h
- // 43_KeyValuePath
- //
- // Created by jiangwei on 14-10-15.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- @interface Author : NSObject{
- NSString *_name;
- //作者出版的书,一个作者对应多个书籍对象
- NSArray *_issueBook;
- }
- @end
作者类中定义了名字和一个书籍数组
Author.m
- //
- // Author.m
- // 43_KeyValuePath
- //
- // Created by jiangwei on 14-10-15.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import "Author.h"
- @implementation Author
- @end
Book.h
- //
- // Book.h
- // 43_KeyValuePath
- //
- // Created by jiangwei on 14-10-15.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import "Author.h"
- @interface Book : NSObject{
- Author *_author;
- }
- @property NSString *name;
- @property floatfloat *price;
- @end
定义了一个作者属性,书的名字,价格
Book.m
- //
- // Book.m
- // 43_KeyValuePath
- //
- // Created by jiangwei on 14-10-15.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import "Book.h"
- @implementation Book
- @end
看一下测试代码
main.m
- //
- // main.m
- // 43_KeyValuePath
- //
- // Created by jiangwei on 14-10-15.
- // Copyright (c) 2014年 jiangwei. All rights reserved.
- //
- #import <Foundation/Foundation.h>
- #import "Book.h"
- #import "Author.h"
- int main(int argc, const charchar * argv[]) {
- @autoreleasepool {
- //------------------KVC键值路径
- /*
- Book *book = [[Book alloc] init];
- Author *author = [[Author alloc] init];
- //设置作者
- [book setValue:author forKey:@"author"];
- //设置作者的名字
- //路径为:author.name,中间用点号进行连接
- [book setValue:@"jiangwei" forKeyPath:@"author.name"];
- NSString *name = [author valueForKey:@"name"];
- NSLog(@"name is %@",name);
- */
- //--------------------KVC的运算
- Author *author = [[Author alloc] init];
- [author setValue:@"莫言" forKeyPath:@"name"];
- Book *book1 = [[Book alloc] init];
- book1.name = @"红高粱";
- book1.price = 9;
- Book *book2 = [[Book alloc] init];
- book2.name = @"蛙";
- book2.price = 10;
- NSArray *array = [NSArray arrayWithObjects:book1,book2, nil nil];
- [author setValue:array forKeyPath:@"issueBook"];
- //基本数据类型会自动被包装成NSNumber,装到数组中
- //得到所有书籍的价格
- NSArray *priceArray = [author valueForKeyPath:@"issueBook.price"];
- NSLog(@"%@",priceArray);
- //获取数组的大小
- NSNumber *count = [author valueForKeyPath:@"issueBook.@count"];
- NSLog(@"count=%@",count);
- //获取书籍价格的总和
- NSNumber *sum = [author valueForKeyPath:@"issueBook.@sum.price"];
- NSLog(@"%@",sum);
- //获取书籍的平均值
- NSNumber *avg = [author valueForKeyPath:@"issueBook.@avg.price"];
- NSLog(@"%@",avg);
- //获取书籍的价格最大值和最小值
- NSNumber *max = [author valueForKeyPath:@"issueBook.@max.price"];
- NSNumber *min = [author valueForKeyPath:@"issueBook.@min.price"];
- }
- return 0;
- }
1、首先通过前面说到的KVC设置作者的书籍数组
- //--------------------KVC的运算
- Author *author = [[Author alloc] init];
- [author setValue:@"莫言" forKeyPath:@"name"];
- Book *book1 = [[Book alloc] init];
- book1.name = @"红高粱";
- book1.price = 9;
- Book *book2 = [[Book alloc] init];
- book2.name = @"蛙";
- book2.price = 10;
- NSArray *array = [NSArray arrayWithObjects:book1,book2, nil nil];
- [author setValue:array forKeyPath:@"issueBook"];
添加了两本书籍
2、下面就开始用到KVC中键值路径了
1)获取作者类中书籍数组中所有书籍的价格
- //基本数据类型会自动被包装成NSNumber,装到数组中
- //得到所有书籍的价格
- NSArray *priceArray = [author valueForKeyPath:@"issueBook.price"];
- NSLog(@"%@",priceArray);
看到了:@"issueBook.price" 这就是键值路径的使用,issueBook是作者类中的书籍数组属性名,price是书籍类的属性,中间用点号进行连接,这样我们就可以获取到了所有书籍的价格了,如果在Java中,我们需要用一个循环操作。但是OC中多么方便。
2)获取作者类中书籍数组的大小
- //获取数组的大小
- NSNumber *count = [author valueForKeyPath:@"issueBook.@count"];
- NSLog(@"count=%@",count);
使用 @"issueBook.@count" 键值路径获取书籍数组的大小,issueBook是作者类中的书籍数组属性名,@count是特定一个写法,可以把它想象成一个方法,中间任然用点号进行连接
3)获取作者类中书籍数组的价格总和
- //获取书籍价格的总和
- NSNumber *sum = [author valueForKeyPath:@"issueBook.@sum.price"];
- NSLog(@"%@",sum);
使用 @"issueBook.@sum.price" 键值路径获取书籍数组中的价格总和,issueBook是作者类中的书籍数组属性名,@sum是特性写法,可以把它想象成一个方法,price是书籍的价格属性名,可以把它看成是@sum的一个参数,中间用点号进行连接
如果在java中,这个需要用一个循环来计算总和,OC中很方便的
4)获取作者类中书籍数组的价格平均值、最小值、最大值
- //获取书籍的平均值
- NSNumber *avg = [author valueForKeyPath:@"issueBook.@avg.price"];
- NSLog(@"%@",avg);
- //获取书籍的价格最大值和最小值
- NSNumber *max = [author valueForKeyPath:@"issueBook.@max.price"];
- NSNumber *min = [author valueForKeyPath:@"issueBook.@min.price"];
操作和上面类似,这里就不解释了
我们看到上面返回来的数据都是NSNumber类型的
三、观察者模式
#import <Foundation/Foundation.h> /*
观察者模式(通知模式)NSNotification
观察者中心 NSNotificationCenter 注册观察者必需在[发出通知]之前 */ @interface House : NSObject -(void) burn; @end #import "House.h" @implementation House -(void)burn
{
NSLog(@"房子着火了");
// 发出通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"PlanB" object:nil];
}
@end #import <Foundation/Foundation.h> @interface Child : NSObject -(void) loudSay; -(void) toBeAGuanChazhe; @end #import "Child.h" @implementation Child -(void) loudSay
{
NSLog(@"报告:房子着火了");
} -(void)toBeAGuanChazhe
{
// 创建观察者
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loudSay) name:@"PlanB" object:nil];
}
@end #import <Foundation/Foundation.h> #import "House.h"
#import "Child.h" int main(int argc, const char * argv[]) {
@autoreleasepool { House *myhouse = [[House alloc] init]; Child *mychild = [[Child alloc] init]; // 让mychild 成为观察者
[mychild toBeAGuanChazhe]; // 让房子着火,发出PlanB现象
[myhouse burn];
}
return ;
}
四、KVO
#import <Foundation/Foundation.h>
#import "JieCao.h" /*
KVO key-value-observer(键值观察) 作用:能够在被观察的某个属性发生变化的时候,自动执行某些方法 当被观察的某个属性发生变化的时候,这个方法被自动回调 -(void) observer... pss:当键值观察的观察者被使用完毕之后必须注销
psss:键值观察是在[某个类中]给[某个属性] 注册观察者,当这个属性的值发生变化后作出响应模式 */ @interface Bowen : NSObject @property (strong,nonatomic) JieCao *my_jieCao; @end #import "Bowen.h" @implementation Bowen -(void) setMy_jieCao:(JieCao *)my_jieCao
{
_my_jieCao = my_jieCao; //注册观察者,观察_my_jieCao属性的值的变化
[_my_jieCao addObserver:self forKeyPath:@"jieCaoValue" options:NSKeyValueObservingOptionNew context:nil]; }
// 不管在一个类当中注册一个多少KVO的观察者,本方法只能写一个
-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"jieCaoValue"]) { if ([[change objectForKey:@"new"] integerValue]<) {
NSLog(@"我要吐了,受不了老师了");
}
// NSLog(@"keyPath:%@",keyPath);
// NSLog(@"Object:%@",keyPath);
// NSLog(@"change:%@",[change objectForKey:@"new"]); }
}
- (void)dealloc
{
[_my_jieCao removeObserver:self forKeyPath:@"jieCaoValue"];
} @end #import <Foundation/Foundation.h> @interface JieCao : NSObject @property (assign, nonatomic) NSInteger jieCaoValue; @end #import "JieCao.h" @implementation JieCao @end #import <Foundation/Foundation.h> #import "Bowen.h"
#import "JieCao.h" int main(int argc, const char * argv[]) {
@autoreleasepool {
// 创建被观察属性
JieCao *jieCao = [[JieCao alloc] init];
jieCao.jieCaoValue = ;
// 创建观察对象
Bowen *bowen = [[Bowen alloc] init];
// 让观察对象开始观察[被观察属性]
bowen.my_jieCao = jieCao;
// 让被观察属性发生变化
bowen.my_jieCao.jieCaoValue = ;
}
return ;
}
五、工厂模式
#import <Foundation/Foundation.h>
#import "Fruit.h" /* 工厂模式:(工厂方法) 个人理解:实际上就是用来快速大批量生产对象的 优点:能够将原本在本类初始化的对象,延时到子类中去初始化。实现了一个开放封闭原则。 */ @interface FruitFactory : NSObject // 通过外部输入的名字,创建[名字对应的类] 的对象
+ (Fruit *)createFruitByName:(NSString *) name; @end #import "FruitFactory.h" @implementation FruitFactory +(Fruit *)createFruitByName:(NSString *)name
{
//需要知道名字对应的类
Class class = NSClassFromString(name);
// 创建想要的类对象
Fruit *fruit = [[class alloc] init];
// 返回新建的[想要的类]的对象
return fruit;
}
@end #import <Foundation/Foundation.h> @interface Fruit : NSObject -(void) show; @end #import "Fruit.h" @implementation Fruit -(void)show
{
NSLog(@"I'm fruit");
}
@end #import "Fruit.h" @interface Apple : Fruit @end #import "Apple.h" @implementation Apple -(void)show
{
NSLog(@"I'm apple");
} #import "Fruit.h" @interface Banana : Fruit @end #import "Banana.h" @implementation Banana -(void)show
{
NSLog(@"I'm banana");
} @end #import "Fruit.h" @interface Pear : Fruit @end #import "Pear.h" @implementation Pear -(void)show
{
NSLog(@"I'm pear");
} @end #import <Foundation/Foundation.h>
#import "FruitFactory.h" int main(int argc, const char * argv[]) {
@autoreleasepool {
Fruit *fruit = [FruitFactory createFruitByName:@"Apple"];
[fruit show];
Fruit *fruit1 = [FruitFactory createFruitByName:@"Banana"];
[fruit1 show];
Fruit *fruit2 = [FruitFactory createFruitByName:@"Pear"];
[fruit2 show];
}
return ;
}
OC 设计模式的更多相关文章
- OC—设计模式-通知的使用
通知 通知(广播) 可以一对多的发送通知(一个发送者 多个观察者) 特别注意:在发送者 发送通知的时候,必须有观察者 发送者,就是注册一个通知中心,以他为中心,发送消息 通过通知的名字,来判断是哪个通 ...
- OC 设计模式——单例模式
单例模式的作用:可以保证在程序运行过程,一个类只有一个实例,而且这个实例易于供外界访问.永远只分配一次内存给这个类.由于在调用alloc方法的时候,都会调用allocWithZone,所以要重写这个方 ...
- [转载]iOS面试题总
转载自:http://blog.sina.com.cn/s/blog_67eb608b0101r6xb.html (2014-06-13 20:23:33) 转载▼ 标签: 转载 crash 原文 ...
- iOS 面试题 2
1. 描述应用程序的启动顺序. 1.程序入口main函数创建UIApplication实例和UIApplication代理实例 2.在UIApplication代理实例中重写启动方法, ...
- iOS 面试题整理(带答案)二
第一篇面试题整理: http://www.cocoachina.com/bbs/read.php?tid-459620.html 本篇面试题同样:如答案有问题,欢迎指正! 1.回答person的ret ...
- iOS 重构AppDelegate
一.Massive AppDelegate AppDelegate 是应用程序的根对象,它连接应用程序和系统,确保应用程序与系统以及其他应用程序正确的交互,通常被认为是每个 iOS 项目的核心. 随着 ...
- 设计模式之观察者模式(关于OC中的KVO\KVC\NSNotification)
学习了这么久的设计模式方面的知识,最大的感触就是,设计模式不能脱离语言特性.近段时间所看的两本书籍,<大话设计模式>里面的代码是C#写的,有一些设计模式实现起来也是采用了C#的语言特性(C ...
- OC中的单例设计模式及单例的宏抽取
// 在一个对象需要重复使用,并且很频繁时,可以对对象使用单例设计模式 // 单例的设计其实就是多alloc内部的allocWithZone下手,重写该方法 #pragma Person.h文件 #i ...
- 【OC加强】辛格尔顿和[NSFileManager defaultMagager]以及其他设计模式
我们在工作中使用文件NSFileManager上课时间,创建发现1对象,此2同样的对象地址: NSFileManager *file1=[NSFileManager defaultManager]; ...
随机推荐
- 高并发下,php使用uniqid函数生成唯一标识符的四种方案
PHP uniqid()函数可用于生成不重复的唯一标识符,该函数基于微秒级当前时间戳.在高并发或者间隔时长极短(如循环代码)的情况下,会出现大量重复数据.即使使用了第二个参数,也会重复,最好的方案是结 ...
- Jsoup请求http或https返回json字符串工具类
Jsoup请求http或https返回json字符串工具类 所需要的jar包如下: jsoup-1.8.1.jar 依赖jar包如下: httpclient-4.5.4.jar; httpclient ...
- TI 实时操作系统SYS/BIOS使用总结
1:概述: SYS/BIOS 是一个可扩展的实时的操作系统.具有非常快速的响应时间(在中断和任务切换时达到较短的延迟),响应时间的确定性,强壮的抢占系统,优化的内存分配和堆栈管理(尽量少的消耗和碎片) ...
- 一种新的技术,C++/CLI
一.来源 在一个项目中,拿到了一个demo,看起来像是C#,又像是C++,部分截图如下 1.界面[C#的winform] 2.mian入口,是cpp 3.解决方案 二.猜测 一开始以为是C#工程,因为 ...
- 分析linux内核中的slub内存管理算法
1. 分析的linux内核源码版本为4.18.0 2. 与slub相关的内核配置项为CONFIG_SLUB 3. 一切都从一个结构体数组kmalloc_caches开始,它的原型如下: ] __ro_ ...
- JavaScript 开闭原则OCP
代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3. ...
- url rewrite导致的500.19 0x8007000d
https://stackoverflow.com/questions/13532447/http-error-500-19-iis-7-5-error-0x8007000d It seems you ...
- java 关于wait,notify和notifyAll
public synchronized void hurt() { //... this.wait(); //... } public synchronized void recover() { // ...
- Codeforces Round #429 (Div. 2)
A. Generous Kefa One day Kefa found n baloons. For convenience, we denote color of i-th baloon as ...
- 自动化测试框架Cucumber和RobotFramework的实战对比
转自: http://www.infoq.com/cn/articles/cucumber-robotframework-comparison 一.摘要 自动化测试可以快速自动完成大量测试用例,节 ...