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]; ...
随机推荐
- Python Web学习笔记之TCP、UDP、ICMP、IGMP的解释和区别
TCP与UDP解释 TCP---传输控制协议,提供的是面向连接.可靠的字节流服务.当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据.TCP提供超时重发,丢弃重复数据, ...
- CF620E New Year Tree 线段树 dfs序
luogu链接 题目大意: 有一个节点有颜色的树 操作1.修改子树的颜色 操作2.查询子树颜色的种类 注意,颜色种类小于60种 只有子树的操作,dfs序当然是最好的选择 dfs序列是什么,懒得讲了,自 ...
- Wireshark过滤总结
Wireshark提供了两种过滤器:捕获过滤器:在抓包之前就设定好过滤条件,然后只抓取符合条件的数据包.显示过滤器:在已捕获的数据包集合中设置过滤条件,隐藏不想显示的数据包,只显示符合条件的数据包.需 ...
- 打印图形|2014年蓝桥杯B组题解析第五题-fishers
打印图形 小明在X星球的城堡中发现了如下图形和文字: rank=3 rank=5 rank = 6 小明开动脑筋,编写了如下的程序,实现该图形的打印. 答案:f(a, rank-1, row, col ...
- Sql 最简单的Sqlserver连接
string name = txtUserName.Text.Trim();//移除用户名前部和后部的空格 string pwd = txtUserPwd.Text.Trim();//移除密码前部和后 ...
- spring boot 启动后执行初始化方法
http://blog.csdn.net/catoop/article/details/50501710 1.创建实现接口 CommandLineRunner 的类 package org.sprin ...
- C#学习笔记(九):函数、代码查询和调试
代码查询和调试 代码查询 using System; using System.Collections.Generic; using System.Linq; using System.Text; u ...
- jquery.cookie.js中$.cookie() 使用方法
定义:让网站服务器把少量数据储存到客户端的硬盘或内存,从客户端的硬盘读取数据的一种技术: 下载与引入:jquery.cookie.js基于jquery:先引入jquery,再引入:jquery.coo ...
- 深度优先搜索初尝试-DFS-LakeCounting POJ No.2386
DFS入门的一道经典题目:LakeCounting 用栈或队列来实现: #include<cstdio> #include<stdlib.h> #include<iost ...
- NOI 7614 最低通行费(多段图最短路)
http://noi.openjudge.cn/ch0206/7614/ 题意: 有一个N*N的正方形网格,商人从网格的左上角进,右下角出.每穿越中间1个小方格,都要花费1个单位时间.商人必须在(2N ...