单例。单:唯⼀性。例:实例对象。即使用某个类创建的对象是程序中唯⼀的实例对象。
注:通常每次使⽤ alloc 创建的是不同的对象。
如果⼀个类只能创建⼀个对象,称为单例类。单例类可以是⼯具类,视图类,控制器类。
使用场景
某些时候,程序中的多个类需要使⽤同⼀个变量。如何处理?将变量定义在单例类中,则所有类在操作这个变量时都很⽅便容易。
思考:
通讯录的列表⻚面、添加⻚面、编辑⻚面需要同⼀个数据源,如何提供数据源才更⽅便操作?
导航控制器从 firstVC 展⽰到 thirdVC ,如何将值从 firstVC 传⼊ thirdVC ?
使用方法:
定义单例类。
定义创建单例对象的方法 ( 类⽅法 ) 。
根据需要实现伪单例或完整单例。
注意:
操作单例对象的变量存储在静态区,程序关闭后由系统⾃动回收。
单例对象存储在堆区,不释放,程序关闭后由系统⾃动回收。
变量和单例对象的生命周期与程序同步。
优势
在内存中只有⼀个对象,节省内存空间。
避免频繁的创建销毁对象,可以提⾼性能。
避免对共享资源的多重占⽤。
可以全局访问。
降低模块之间的耦合度,降低代码的复杂度。
单例模式
单例模式是⼀种设计模式。
实现:定义⼀个单例类,保证程序中这个类只能创建唯⼀的实例对象,实现资源共享。
//*************************************************
单例
在程序中只创建一个对象,程序当中有很多对象,我们只需要一个就可以了
单例传值,类似于一个仓库的存在
单例还有作用是保存数据,临时保存数据
单例还可以做工具,学网络解析的时候,可以写一个解析类
单例的创建:SingleHendel类中的三步操作,目前不涉及多线程,所以这种方法现在是没问题的,如果涉及到多线程的话还需要做一些其他事情
单例传值
用单例解决一类问题 称为一种设计模式,叫单例模式
自己写程序的话 建议用伪单例
如果写的是第三方框架 建议使用完整单例 (完整单例需要重写很多方法)
今天学的是伪单例
//*************************************************
//++++++++++++++++++++++++++++++++
非常重要的数据共享的方法
什么是单例:
其实就是c中的全局变量 单例和全局变量是等同的
在整个程序生命周期内,该对象只有一份存在内存中
可以在多个对象之间共享数据
什么是单例设计模式
单独的一个对象,很多指针指向它
多个对象之间共享数据
典型的单例写法:
//创建一个对象
static id sharedMyManager;
+(id)sharedThemeManger{
if(sharedMyManager == nil){
//第一次进入调用,把s存于全局变量中
sharedMyManager = [[self alloc]init];
}
//第2次,第3次。。。。都会使用第一次的创建好的变量
return sharedMyManager;
}
//这种写法有个问题:如果多个线程同时调用这个函数 ,可能会创建多个对象,这样有可能会造成内存泄露问题,所以需要我们改一下.
//1 改成一个加锁的方式:
+(id)sharedThemeManger{
//@synchronized(self)让这段代码处于atomic状态
//如果多个线程进入这段代码 这段代码只能是一个线程执行
@synchronized(self){
if(sharedMyManager == nil){
sharedMyManager = [[self alloc]init];
}
}
return sharedMyManager;
}
//2 第一次实例化创建Lock free 免锁写法
+(voidq)initialize{
static BOOL initialized = NO;
if(initialized == NO){
initialized = YES;
sharedMyManager = [[self alloc]init];
}
}
//3 GCD写法:(推荐使用)
+(id)sharedManager{
static dispatch_once_t onceToken;
//dispatch_once 就是保证了blocks只能执行一次
dispatch_once(&onceToken,^{
if(s == nil){
s = [[[self class]alloc]init];
}
});
return sharedMyManager;
}
//单例的正确调用方法:
ThemeManager * tm2 = [ThemeManager sharedThemeManager];
//单例方法的调用要避免以下形式(虽然完整的单例写法中允许这样写,但是不建议这样):
ThemeManager * tm4 = [[ThemeManager alloc]init];
ThemeManager * tm5 = [tm4 copy];
//要完整的写一个单例,需要重载下面五个方法(ARC模式不需要下面三个)
+(id) allocWithZone:(NSZone *)zone;
+(id) copyWithZone:(NSZone *)zone;
-(id) retain;
-(void) release;
-(void) autorelease;
+(id) allocWithZone:(NSZone *)zone{
//alloc 会用
return [[self sharedThemeManager]retain];
}
+(id) copyWithZone:(NSZone *)zone{
return self;
}
-(id) retain{
return self;
}
-(oneway void) release{
}
-(void) retainCount{
//对计数器返回一个最大数
return UINT_MAX;
}
-(id)autorelease{
return self;
}
单例不建议使用alloc创建,直接用类方法创建
//++++++++++++++++++++++++++++++++
=================================
AppDelegate.m
#import "AppDelegate.h"
#import "RootViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
RootViewController * rootVC = [[RootViewController alloc]init];
UINavigationController * rootNC = [[UINavigationController alloc]initWithRootViewController:rootVC];
self.window.rootViewController = rootNC;
return YES;
}
@end
RootViewController.m
#import "RootViewController.h"
#import "SingleHandle.h"
#import "NextViewController.h"
@interface RootViewController ()
@property(nonatomic,strong)UITextField * rootTextField;
@end
@implementation RootViewController
//***
-(void)viewWillAppear:(BOOL)animated{
self.rootTextField.text = [SingleHendel shareSingle].aString;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor yellowColor];
/*
#warning test
SingleHandle *s1 = [SingleHandle shareSingle];
SingleHandle *s2 = [SingleHandle shareSingle];
//打印看地址是否一样 一样说明创建出来的对象是同一个
NSLog(@"s1:%p",s1);
NSLog(@"s2:%p",s2);
*/
//创建textField
self.rootTextField = [[UITextField alloc]initWithFrame:CGRectMake(50, 80, 250, 50)];
self.rootTextField.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_rootTextField];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NextViewController * nextVC = [[NextViewController alloc]init];
// ****给单例赋值
[SingleHandle shareSingle].aString = self.rootTextField.text;
[self.navigationController pushViewController:nextVC animated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
NextViewController.m
#import "NextViewController.h"
#import "SingleHandle.h"
@interface NextViewController ()
@property(nonatomic,strong)UITextField * nextTextField;
@end
@implementation NextViewController
-(void)viewWillAppear:(BOOL)animated{
//****从单例中取值
self.nextTextField.text = [SingleHandle shareSingle].aString;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor greenColor];
//创建nextTextField
self.nextTextField = [[UITextField alloc]initWithFrame:CGRectMake(50, 80, 250, 50)];
self.nextTextField.backgroundColor = [UIColor whiteColor];
[self.view addSubview:_nextTextField];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//****POP之前 给单例属性赋值
[SingleHandle shareSingle].aString = self.nextTextField.text;
[self.navigationController popToRootViewControllerAnimated:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
SingleHandle.h
#import <Foundation/Foundation.h>
@interface SingleHandle : NSObject
@property(nonatomic,copy)NSString * aString;
//创建单例第一步
+(instancetype)shareSingle;
@end
SingleHandle.m
#import "SingleHandle.h"
//第二步 定义静态变量 (生命周期是整个程序)
static SingleHandle* sh = nil;
@implementation SingleHandle
//创建单例第一步 实现方法
//伪单例 (和这个伪单例对应的是完整单例)
+(instancetype)shareSingle{
//第三步 判断是否为空,是 则创建
if (sh == nil) {
sh = [[SingleHandle alloc]init];
}
return sh;
}
@end
//