您的位置:首页 > 移动开发 > Objective-C

Objective-C学习-单例以及通知中心(NotificationCenter)

2015-11-03 15:01 507 查看

单例

单例是什么呢,简单的来说就是一块全局唯一的内存,通俗的来讲就是一块全局共用的内存,那么单例有什么用呢,楼主表示基本上自己写过的单例大多数都是用来传值的或者打包成一个功能性的类,当然方法自然不唯一,但是单例算是比较好用,而且也是最好理解的一种方法了。
首先先来看如何写单例,因为在之前的博客中大多数的单例都习惯叫做Manager,所以这次测试的单例就写作TestManager(测试管理者),声明方法如下
//
//  TestManager.h
//  单例以及通知中心(博客)
//
//  Created by YueWen on 15/11/3.
//  Copyright © 2015年 YueWen. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface TestManager : NSObject

/**
*  测试的字符串
*/
@property(nonatomic,strong)NSString * testString;

/**
*  获取单例的方法,名字一般比较固定,开始基本是share,standard,default..
*
*  @return 单例对象
*/
+(instancetype)shareInstance;

@end


在之前楼主学的时候,看网上的视频也好,文字也好,单例的写法分为很多很多种,什么加锁啊,整的都快疯了,特别是初学者,那么GCD也早给大家打包好一个写单例的方法,简洁又好看,如下

+(instancetype)shareInstance
{
static TestManager * testManager = nil;

static dispatch_once_t onceToken;//表示只执行一次
dispatch_once(&onceToken, ^{

testManager = [[TestManager alloc]init];

});

return testManager;
}


那么如何共享数据的呢,就用里面的测试字符串来瞅瞅,直接在viewDidLoad里来进行测试,用main方法也是可以的,只不过楼主习惯性的建立了iphone的工程了。

代码如下,相信都看的明白:

- (void)viewDidLoad {
[super viewDidLoad];

//初始化第一个单例
TestManager * testManager1 = [TestManager shareInstance];

//初始化第二个单例
TestManager * testManager2 = [TestManager shareInstance];

//修改单例的属性
testManager1.testString = @"我是testManager1设置的值";

//打印输出
NSLog(@"\n---第一次测试----\ntestManager1调用属性:%@",testManager1.testString);
NSLog(@"testManager2调用属性:%@\n",testManager2.testString);

//通过testManager2来修改属性
testManager2.testString = @"我是testManager2设置的值";

//打印测试
NSLog(@"\n---第二次测试----\ntestManager1调用属性:%@",testManager1.testString);
NSLog(@"testManager2调用属性:%@\n",testManager2.testString);

}


打印结果呢:



从结果来看,第一次没有用testManager2来修改值,但是他也有值,第二次用testManager2修改值后,testManaegr1也由此拥有了值,可以看出,他们共用了同一个内存空间,那么他和传统的alloc init的区别呢,也因此用alloc init写了一个测试

- (void)viewDidLoad {
[super viewDidLoad];

//初始化第一个单例
TestManager * testManager1 = [[TestManager alloc]init];//这里没有用shareInstance

//初始化第二个单例
TestManager * testManager2 = [[TestManager alloc]init];//这里也没有用到shareInstance

//修改单例的属性
testManager1.testString = @"我是testManager1设置的值";

//打印输出
NSLog(@"\n---第一次测试----\ntestManager1调用属性:%@",testManager1.testString);
NSLog(@"testManager2调用属性:%@\n",testManager2.testString);

//通过testManager2来修改属性
testManager2.testString = @"我是testManager2设置的值";

//打印测试
NSLog(@"\n---第二次测试----\ntestManager1调用属性:%@",testManager1.testString);
NSLog(@"testManager2调用属性:%@\n",testManager2.testString);

}


结果如下:



从结果来看,用alloc init的意思就是重新初始化一块内存,testManager1与testManager2没有任何的关系,是完全不同的两块内存,而单例不是,单例是公用的一块内存,所以一方修改,另一个也是修改的。

通知中心(NSNotificationCenter)

通知中心,一听感觉很高大上,那么他有什么用呢,之前的博客中提及过KVO,键值观察,也欢迎去了解一下 objective-C学习-KVC(键值编码)和KVO(键值观察),通知中心与KVO同为观察者模式的一种表现。
通知中心什么时候用呢,比如两个ViewController之间进行传值,当然可以用自己写的单例进行传值,但是如果有一个值发生变化,需要另一个ViewController立马发生变化呢,这种情况下还是可以用回调的,那么一个ViewController发生变化,需要多个ViewController都要接收到呢,这个时候相信用回调是比较麻烦的,这个时候通知中心就为开发者提供了更大的便利,怎么用呢,首先说明通知中心(NSNotificationCenter)是一个单例,声明方法如下:
//通知中心的声明
NSNotificationCenter * notificationCenter = [NSNotificationCenter defaultCenter];


发送通知如何呢,苹果里面有一个NSNotification(通知的类),通知中心说到底就是发送通知的,通过创建一个通知,并且发送通知的方法如下:
/**
*  通知的创建
*
*  @param NSString 通知的名字
*  @param object   发送通知的人
*  @param userInfo 附带的信息,是一个字典,不传值的时候设置为nil即可
*
*  @return 创建的通知
*/
NSNotification * notification = [NSNotification notificationWithName:@"test1" object:self userInfo:nil];

//发送通知
[notificationCenter postNotification:notification];


这样子写是不是显得繁琐呢,通知中心也提供了方法简便上面的操作,下面与上面的作用是一模一样的
//发送通知
[notificationCenter postNotificationName:@"test1" object:self userInfo:nil];


那么如果有发送通知,如何知道它发了通知呢,必然会出现一个相对应的预定通知,如下
/**
*  通知中心预定
*
*  @param NSString 通知的名字
*  @param object   接受谁的通知,nil表示接受所有的同名通知
*  @param queue    队列,一般为主队列,为nil时表示发送通知的那个线程
*
*  @return 接受通知的操作
*/
[notificationCenter addObserverForName:@"test1" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {

//接收到通知后进行的操作
NSLog(@"通知已经接收到!");
}];


如果订阅了通知,不要忘记取消啊,就和KVO一样,观察了记得取消,取消方式如下
//取消订阅通知中心
[notificationCenter removeObserver:self];


用法如上,那么就要通知中心来写点东西来测试一下吧,注意一点就是一定要先订阅再发送,不然是接收不到通知的.

为了测试,那么首先创建两个测试类,分别叫做Test1与Test2,因为只是测试,因此只写了init方法,就是说只要创建这个对象,就订阅了通知,方法如下
@implementation Test1

-(instancetype)init
{
if (self = [super init])
{
//订阅通知
[[NSNotificationCenter defaultCenter]addObserverForName:@"lalala" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {

NSLog(@"Test1接受到了通知,内容是%@",note.userInfo[@"userInfo"]);
}];
}
return self;
}


@implementation Test2

- (instancetype)init
{
self = [super init];
if (self) {

//订阅通知
[[NSNotificationCenter defaultCenter]addObserverForName:@"lalala" object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {

NSLog(@"Test2接收到通知啦!内容是%@",note.userInfo[@"userInfo"]);

}];
}
return self;
}


接下来就需要在ViewController中的viewDidLoad中进行测试,首先在延展中声明两个属性
@property(nonatomic,strong)Test1 * test1;//测试类1
@property(nonatomic,strong)Test2 * test2;//测试类2


在viewDidLoad中初始化两个属性,并且发送通知即可
- (void)viewDidLoad {
[super viewDidLoad];

//实例化属性
self.test1 = [[Test1 alloc]init];
self.test2 = [[Test2 alloc]init];

//发送通知
[[NSNotificationCenter defaultCenter]postNotificationName:@"lalala" object:self userInfo:@{@"userInfo":@"RunIntoLove"}];

}


运行结果如下:



可以看出,字符串的值已经传过去了,并且对于一对多的传值,通知中心拥有不可替代的作用,方便并且更加容易操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: