iOS中的单例模式
来源:互联网 发布:数值的整数次方 java 编辑:程序博客网 时间:2024/06/10 00:00
单例模式是指一个类中只能有一个实例的时候,下面是我学习单例中遇到的情况。
单例模式有两种创建方式,一种是将创建代码包裹在同步块里,另一种是使用GCD的一项特性。
我们先看第一种:
+(id)sharedInstance{ static MyClass *className = nil; // 同步,线程安全 @synchronized(self) { if (!className) { className = [[self alloc] init]; } } return className;}第二种方法是苹果官方推荐的方法,使用GCD的dispatch_once(dispatch_once_t *token, dispatch_block_t block)方法,该方法中有两个参数,第一个参数类型为dispatch_once_t的特殊参数,可以将其称为“标记”(token),该参数的作用是保证相关的块必须执行,而且只能执行一次,既区分作用。因为只能执行一次,所以每次调用函数时传入的“标记”都必须完全相同,所以通常将dispatch_once_t的参数声明在static或global作用于里。
+(id)sharedInstance{ static MyClass *className = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ className = [[self alloc] init]; }); return className;}使用dispatch_once可以简化代码并且彻底保证线程安全。下面是我要测试的demo
我要执行的任务是,点击按钮,弹出一个登录框,登录框有用户名的输入框和一个确定按钮,点击确定按钮,登陆界面消失。
这是主界面代码
#import "ViewController.h"#import "LoginDetailsView.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad{ [super viewDidLoad]; [self createButton]; // Do any additional setup after loading the view, typically from a nib.}#pragma mark - 设置跳转按钮-(void)createButton{ UIButton *button = [UIButton buttonWithType:0]; button.frame = CGRectMake(100, 350, 120, 50); button.backgroundColor = [UIColor redColor]; [button setTitle:@"跳转登陆界面" forState:UIControlStateNormal]; [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; [button addTarget:self action:@selector(jumpAnotherView) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button];}#pragma mark - 跳转下一个页面-(void)jumpAnotherView{ LoginDetailsView __block *loginView = [LoginDetailsView sharedInstance:CGRectMake(20, 30, self.view.frame.size.width - 40, 300)]; //LoginDetailsView *loginView = [[LoginDetailsView alloc] initWithFrame:CGRectMake(20, 30, self.view.frame.size.width - 40, 300)]; [loginView setSureButtonClick:^(NSString *title, NSInteger count) { NSLog(@"title = %@, count = %ld", title, (long)count); }]; [self.view addSubview:loginView];}这是登陆界面代码
#import <UIKit/UIKit.h>typedef void (^sureButtonClickBlock) (NSString *title, NSInteger count);@interface LoginDetailsView : UIView@property (nonatomic, strong) sureButtonClickBlock sureButtonClick;// 采用单例模式创建界面+(id)sharedInstance:(CGRect)frame;// 销毁单例//-(void) destroySingleTon;-(void)setSureButtonClick:(sureButtonClickBlock)sureButtonClick;@end
#import "LoginDetailsView.h"#import "GBDIYButton.h"#import "GBDIYTextfield.h"@interface LoginDetailsView (){ GBDIYButton *sureButton; // 确定按钮 GBDIYTextfield *userNameField; // 用户名输入框}@end@implementation LoginDetailsView-(id)initWithFrame:(CGRect)frame{ if (self == [super initWithFrame:frame]) { self.backgroundColor = [UIColor yellowColor]; // 初始化界面 [self createLoginView]; } return self;}static LoginDetailsView *loginDetailsView;+(id)sharedInstance:(CGRect)frame{ static LoginDetailsView *loginDetailsView = nil; // 同步,线程安全 @synchronized(self) { if (!loginDetailsView) { loginDetailsView = [[self alloc] initWithFrame:frame]; } } return loginDetailsView;}//#pragma mark - 使用dispatch_once创建单例//+(id)sharedInstance:(CGRect)frame//{// static LoginDetailsView *loginDetailsView = nil;// static dispatch_once_t onceToken;// // dispatch_once(&onceToken, ^{// loginDetailsView = [[self alloc] initWithFrame:frame];// });// // return loginDetailsView;//}#pragma mark - 初始化界面-(void)createLoginView{ userNameField = [[GBDIYTextfield alloc] initWithFrame:CGRectMake(30, 50, self.frame.size.width - 60, 40) withPlaceHolder:@"请输入用户名"]; [self addSubview:userNameField]; sureButton = [[GBDIYButton alloc] initWithFrame:CGRectMake(self.frame.size.width / 2.0 - 30, self.frame.size.height - 100, 60, 40) withTitle:@"确定"]; [sureButton addTarget:self action:@selector(clickTheButton) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:sureButton];}-(void)setSureButtonClick:(sureButtonClickBlock)sureButtonClick{ if (sureButtonClick) { _sureButtonClick = sureButtonClick; }}#pragma mark - 点击按钮操作-(void)clickTheButton{ /* * 再此处写请求网络之类的代码,请求成功,本登陆界面消失 */ [self removeFromSuperview]; if (self.sureButtonClick) { NSNumber *number = [NSNumber numberWithInt:2]; NSInteger count = [number integerValue]; self.sureButtonClick(@"点击确定按钮", count); }}//-(void) destroySingleTon//{// loginDetailsView = nil;//}
<span style="color:#ff0000;">自定义输入框代码</span>
<pre name="code" class="objc">#import <UIKit/UIKit.h>@interface GBDIYTextfield : UITextField// 自定义初始化方法-(id)initWithFrame:(CGRect)frame withPlaceHolder:(NSString *)placeHolder;@end
#import "GBDIYTextfield.h"@implementation GBDIYTextfield-(id)initWithFrame:(CGRect)frame withPlaceHolder:(NSString *)placeHolder{ if (self == [super initWithFrame:frame]) { self.placeholder = placeHolder; self.layer.borderColor = [UIColor lightGrayColor].CGColor; self.layer.borderWidth = 1; self.layer.cornerRadius = 15; } return self;}@end
<span style="color:#ff0000;background-color: rgb(255, 255, 255);">自定义按钮代码</span>
<pre name="code" class="objc">#import <UIKit/UIKit.h>@interface GBDIYButton : UIButton// 自定义初始化方法-(id)initWithFrame:(CGRect)frame withTitle:(NSString *)title;@end
#import "GBDIYButton.h"@implementation GBDIYButton-(id)initWithFrame:(CGRect)frame withTitle:(NSString *)title{ if (self == [super init]) { self.frame = frame; [self setTitle:title forState:UIControlStateNormal]; [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; self.backgroundColor = [UIColor greenColor]; self.layer.cornerRadius = 10; } return self;}@end通过打断点可知,用传统的方法,alloc init ,在主界面点击“跳转登陆界面”点击一次,生成一次登陆界面,所以我们现在用单例创建登陆界面。其实正常的话,此登陆界面不能用单例来实现,因为取消单例是个非常难得事情。我们稍后介绍,现在我们先介绍单例的用法。
代码中用了两中方式创建单例,并用block返回了按钮点击的事件。
可是现在如果你在输入框中输入了内容,点击“确定”按钮,登录界面消失,我们再次点击“跳转登陆界面”按钮,发现我们上次在输入框中填写的内容还在。这就是为什么这个登录界面不应该用单例来写的原因,因为单例自己管理自己的生命周期,所以用摧毁单例的方法很难。请参考具体文章点击打开链接。链接的文章写得很好,慎用单例。
要想摧毁单例,在主界面中将其设置为nil也不行,点击按钮还是会出现。为此我在登陆界面中写了个摧毁单例的方法,-(void)destroySingleTon;但是还是不行。因为要想摧毁这个单例,不能使用@synchronized或者dispatch_once。可是这样,和普通的声明初始化方法没什么两样,也就不是单例了。所以还是那句话,在你想使用单例前,仔细考虑一下,是否应该使用单例。因为单例一旦创建,其生命周期就归单例自己掌控了。还是请参考链接文章。
0 0
- iOS中的单例模式
- IOS中的单例模式
- IOS 中的单例模式
- iOS中的单例模式
- iOS中的单例模式
- iOS中的单例模式
- iOS中的单例模式
- iOS中的单例模式
- IOS中的单例模式
- IOS中的单例模式
- iOS中的单例模式
- iOS 中的单例模式
- iOS中的单例模式
- iOS中的单例模式
- ios中的单例模式
- iOS中的单例模式
- iOS中的单例模式
- iOS中的单例模式
- 升级数据库的最佳写法
- 文章标题
- 使用苹果企业级开发者账号发布应用程序
- NATS服务器配置详解
- DSP28335定时器和外部输入中断
- iOS中的单例模式
- linux系统下mysql跳过密码验证登录
- Tomcat内存溢出的几点方案
- ${pageContext.request.contextPath} JSP路径问题
- Android中解决scrollview中嵌套listview的listview只显示一行的问题
- leetcode04-Median of Two Sorted Arrays-python
- 对RandomAccessFile类的应用
- 数据库索引
- 利用JSPatch为controller添加View