Objective-C设计模式——单例Singleton(对象创建)

单例

和其它语言的单例产不多,可以说是最简单的一种设计模式了。但是有几个点需要注意下,单例就是一个类只有一个实例。

所以我们要想办法阻止该类产生别的实例,一般语言中都会将构造函数写为private。但是OC中的函数并没有限定符,所以我们需要用一些小技巧来屏蔽这一点。

 

应用场景

类只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方法。

这个唯一的实例只能通过类的子类化进行扩展,而且扩展的对象不会破坏客户端代码。

 

注意

1.OC中单例的实例变量要定义在.m文件

2.OC中单例需要重载allocWithZone:和copyWithZone:方法来防止创建别的实例。

3.单例创建要注意线程安全,不然就可能出现多个实例。

注意问题将会在Demo中讲解

 

Demo

首先先来看一个最常规,的不严谨的单例实现:

复制代码
@implementation Singletonstatic Singleton *sharedInstance;-(Singleton *)sharedInstance
{if(sharedInstance){sharedInstance = [Singleton new];}return sharedInstance;
}@end
复制代码

这看似好像是可以得到单例对象了,但是这可以说是单例的一种变形。绝不能说这就是单例,因为我们可以轻松地通过其他方式来创建对象。

所以我们还要我修改allocWithZone:和copyWithZone:方法(alloc 和 copy 方法实际上就是调用这两个方法)

复制代码
-(id)copyWithZone:(NSZone *)zone
{return [[self class] sharedInstance];
}+(id)allocWithZone:(struct _NSZone *)zone
{return [self sharedInstance];
}
复制代码

可是这就出现另一个问题,在sharedInstance方法里面我们实际调用过allocWithZone:(new 调用 alloc),但是它的alloc被我们重写了,这就会出现错误。所以我们需要修改sharedInstance方法

复制代码
+(Singleton *)sharedInstance
{if(sharedInstance){sharedInstance = [[super allocWithZone:NULL] init];}return sharedInstance;
}
复制代码

这样就可以顺利的返回单例了,而且无法通过其它方式产生实例对象。

看似完美了实际还会有问题出现,因为现在是非线程安全的,可能存在同一时间创建多个实例的情况,所以修改如下

复制代码
+(instancetype)sharedInstance
{static dispatch_once_t once;dispatch_once(&once, ^{sharedInstance = [[super allocWithZone:NULL] init];});return sharedInstance;
}
复制代码

客户端代码如下:

复制代码
        Singleton *singleton = [Singleton sharedInstance];Singleton *singleton2 = [[Singleton alloc] init];Singleton *singleton3 = [singleton copy];[singleton print];[singleton2 print];[singleton3 print];
复制代码

输出结果:

2015-07-21 21:10:32.797 Singleton[42537:10347987] 0x7fff5fbff7a8
2015-07-21 21:10:32.798 Singleton[42537:10347987] 0x7fff5fbff7a8
2015-07-21 21:10:32.798 Singleton[42537:10347987] 0x7fff5fbff7a8

可以看到内存都指向了同一地址。

转载于:https://www.cnblogs.com/pb89/p/4708785.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/405286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SSM在线协同过滤汽车推荐销售系统

SSM毕设分享 基于SSM在线协同过滤汽车推荐销售系统 1 项目简介 Hi,各位同学好,这里是郑师兄! 今天向大家分享一个毕业设计项目作品【】 师兄根据实现的难度和等级对项目进行评分(最低0分,满分5分) 难度系数:3分 工作…

Keil中的Code,RO,RW,ZI分别表示什么?

在使用keil开发STM32应用程序时,点击Build后在Build Output窗口中经常会有如下信息:以前一直好奇这几个参数和实际使用的STM32芯片中Flash和SRAM的对应关系,于是上网搜了一圈,做如下总结:这些参数的单位是Byte图中几个…

linux mmap 内存映射 mmap() vs read()/write()/lseek()

From: http://www.perfgeeks.com/?p723 通过strace统计系统调用的时候,经常可以看到mmap()与mmap2()。系统调用mmap()可以将某文件映射至内存(进程空间),如此可以把对文件的操作转为对内存的操作,以此避免更多的lseek()与read()、write()操作…

[react] React组件的构造函数是必须的吗?

[react] React组件的构造函数是必须的吗? 构造函数并不是必须的,对于无状态组件,内部没有维护自己的state,只接收外部传入的props 是不需要声明构造函数的 个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易&#x…

为什么dos下的com文件都要org 0100h呢?为什么系统启动时要org 07c00h呢

这是因为 .com 载入内存后的起始偏址就是100h. 前面的100h字节是该程序的PSP 部分. 所以, 为了程序中对地址引用的正确, 必需加上org 100h语句。----------------------------------------------------------------------------------------------------------------…

Qt中的TableWidget初始化表头、行高、选中、自动扩展和接受修改

一、需求 设置QT中的TableWidget样式,初始化表头,行高和颜色,行选中,是否修改,是否自动扩展宽度等。 二、代码 void MainWindow::TimerListInit() {QStringList InfHeader;int columnNum;columnNum 7;ui->table…

JTAG、SWD接口定义

版权声明:本文为博主原创文章,转载请注明。 博客已转到 http://blog.csdn.net/upc_xbt https://blog.csdn.net/u014124220/article/details/50829713Jlink仿真器接口仿真器端口连接目标板备注1. VCCMCU电源VCCVCC2. VCCMCU电源VCCVCC3. TRSTTRSTTest ReS…

[leedcode 215] Kth Largest Element in an Array

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element. For example,Given [3,2,1,5,6,4] and k 2, return 5. Note: You may assume k is always valid, 1 ≤ k ≤ arrays lengt…

Ubuntu 修改默认的PDF打开方式

Ubuntu自带了可以打开PDF的文档编辑器,如GIMP和文档查看器,但这些自带的文档编辑器并不是很好用,很可能会产生乱码,以至于不方便…… 由于在WIN下对foxit的产品感觉很满意,并且知道它也为linux做了一个PDF查看器&#…

[react] React组件的构造函数有什么作用?

[react] React组件的构造函数有什么作用? 在react的新的写法中,每一个组件都是一个类,这个很符合es6的语法规范,在es6中要想创建一个对象,就要调用相应的构造函数, react的组件渲染有两种情况,第一种情况是…

高级Linux程序设计第五章:进程间通信

From: http://www.cnblogs.com/forfuture1978/archive/2010/04/29/1723417.html 五种进程间通信的方式: 共享内存(shared memory):其允许多个进程通过读写同一块内存地址来相互通信。 内存映射(Mapped memory):其和共享内存相似,…

Qt 给应用程序添加图标

一、需求 给应用程序.exe添加图标。 二、代码 1、资源文件中添加进去main.ico 32X32pt 2、xxxx.pro文件中 添加RC_ICONS main.ico

#pragma pack(push,1)与#pragma pack(1)的区别

这是给编译器用的参数设置,有关结构体字节对齐方式设置, #pragma pack是指定数据在内存中的对齐方式。#pragma pack (n) 作用:C编译器将按照n个字节对齐。#pragma pack () 作用:取消自定义字节对齐方式…

Drainage Ditches - poj 1273(网络流模板)

题意:1是源点,m是汇点,求出来最大流量,没什么好说的就是练习最大流的模板题 ************************************************************** 先用Edmonds-Karp的算法做一下试试吧重边贡献了 1W,要加上所有的重边才算…

sawmill全方位日志分析大师

Sawmill 是一套崭新的集中式(中文)日志报表系统,除了提供收集设备或服务的日志,整合、分析成有效报表外,并能降低企业成本与信息管理人员减少学习报表时间,且能于全球各地上网即可获得IT信息。 集中式 : 集中整合各式设…

[react] React中在哪捕获错误?

[react] React中在哪捕获错误? 在react 15 极其以前的版本中,组件内的UI异常将中断组件内部状态,导致下一次渲染时触发隐藏异常。React并未提供友好的异常捕获和处理方式,一旦发生异常,应用将不能很好的运行。而React 16版本有所…

VC6.0 控件Radio Button的使用

From: http://www.cppblog.com/Lee7/archive/2007/09/13/32152.html 使用方法: 1.建立一个基于对话框的用用程序,在其中加入三个Radio Button,ID分别为: IDC_RADIO1,IDC_RADIO2,IDC_RADIO3 2.控件的初始化: 在对话框类的OnInitDialog中加入代码: …

Qt 实现QT控件中的QLabel显示图片并自适应显示

一、需求 实现QT控件中的QLabel显示图片,并自适应显示。 二、代码 QImage Image; Image.load(":/image/image/logo.jpg"); QPixmap pixmap QPixmap::fromImage(Image); int with ui->label_logo->width(); int height ui->label_logo->…

linux RTC 驱动模型分析

linux RTC 驱动模型分析RTC(real time clock)实时时钟,主要作用是给Linux系统提供时间。RTC因为是电池供电的,所以掉电后时间不丢失。Linux内核把RTC用作“离线”的时间与日期维护器。当Linux内核启动时,它从RTC中读取时间与日期,…

Install Docker Mac OS X

检查 Mac OS version 要求必须是 OS X 10.6 Snow Leopard or newer to run Boot2Docker安装 Boot2Docker 列表内容下载地址:https://github.com/boot2docker/osx-installer/releases/download/v1.7.0/Boot2Docker-1.7.0.pkg 下载后点击安装,就是按照提示…