【iOS】单例、通知、代理

这篇具有很好参考价值的文章主要介绍了【iOS】单例、通知、代理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

单例模式

什么是单例模式?

单例模式在整个工程中,相当于一个全局变量,就是不论在哪里需要用到这个类的实例变量,都可以通过单例方法来取得,而且一旦你创建了一个单例类,不论你在多少个洁面中初始化调用了这个单例方法取得对象,它们所有的对象都是指向的同一块内存的存储空间(即单例类保证了该类的实例对象是唯一存在的一个)

单例模式的优缺点

优点:

  • 单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。
  • 单例因为类控制了实例化的过程,所以类可以更加灵活的修改实例化的过程

缺点:

  • 单例对象一旦建立,对象指针式保存在静态区,单例对象在堆中分配的内存空间会在应用程序中止后才会被释放(和静态变量相似,只要进程在,单例对象就在)。
  • 单例类无法继承,因此很难进行类的扩展。
  • 单例不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就回引起数据的错误,不能保存彼此的状态。

实现方式

懒汉式:

实现原理和懒加载很想,如果在程序中不适用这个对象,那么就不会创建,只有在你使用代码创建这个对象,才会创建。这种思想在iOS开发中是很重要的,也是最常见的时间换空间的做法 (其实就是在第一次使用单例的时候才进行初始化

我们需要重写alloc方法,这里提供了两种方法,一种是alloc,一种是allocWithZone方法

其实在alloc调用的底层也是allocWithZone方法,所以在此,我们只需要重写allocWithZone方法

id manager;
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    // 在这里判断,为了优化资源,防止多次加锁和判断锁
    if (manager == nil) {
        // 在这里加一把锁(利用本类为锁)进行多线程问题的解决
        @synchronized(self){
            if (manager == nil) {
                // 调用super的allocWithZone方法来分配内存空间
                manager = [super allocWithZone:nil];//处于历史原因,OC不再使用NSZone,选择直接忽略
            }
        }
    }
    return manager;
}

但是这样的话还不够优化,我们还可以使用GCD方法进行一个优化:

首先我们来看一个GCD的API:
dispatch_once一次性代码(只会执行一次):

	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		//此处编写只执行一次的代码(这里main默认是线程安全的)
	});

同时对manager应该使用static以避免被extern进行了操作
这里我们浅讲一下staticextern的区别:

  • static:定义在变量或函数前面,它的含义是改变默认的external链接属性,使它们的作用域限定在本文件内部,这样其他类的文件就不能对它做引用和修改了,保证了单例的一个安全性。
  • extern:修饰符extern用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用,并可以对该变量/函数进行修改”

使用GCD的单例模式,添加了一个初始化单例的类方法来作为外部创建单例对象的接口:

static id manager;
//自定义创建单例的类方法接口
+ (instancetype)sharedManger{
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
        manager = [super allocWithZone:zone];
    });
    return manager;
}

//但是这时候我们还是得确保安全去重写一下allocWithZone方法,否则外部如果采用alloc的方法来创建单例对象的时候就会每alloc一遍就会新创建一个该对象,单例就失去了意义
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    if (manager == nil) {
        manager = [super allocWithZone:zone];
    }
    return manager;
}

饿汉式:

在使用代码去创建对象之前就已经创建好了对象。

  1. load方法:当类加载到运行环境中的时候就会调用且仅调用一次,同时注意一个类只会加载一次(类加载有别于引用类,可以这么说,所有类都会在程序启动的时候加载一次,不管有没有在目前显示的视图类中引用到,这个涉及到了App的启动流程)
  2. initialize方法:当第一次使用类的时候加载且仅加载一次

我们再来考虑:

  • 在不考虑开发者主动使用的情况下,系统最多会调用一次
  • 如果父类和子类都被调用,父类的调用一定在子类之前
  • 都是为了应用运行前创建合适的运行环境

在使用时都不要过重地依赖于这两个方法,除非真正必要
它们的相同点在于:方法只会被调用一次。

二者相比较:

load 是只要类所在文件被引用就会被调用,而 initialize 是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load调用;但即使类文件被引用进来,但是没有使用,那么 initialize 也不会被调用。

它们的相同点在于:方法只会被调用一次。

所以选择load

static id manager;
+ (void)load {
    //只会加载一次也就不需要加锁
    manager = [[self alloc] init];
}

+ (instancetype)sharedManger{
    if (manager == nil) {
    	manager = [super allocWithZone:zone];
    }
    return. manager;
}

//但是这时候我们还是得确保安全去重写一下allocWithZone方法,否则外部如果采用alloc的方法来创建单例对象的时候就会每alloc一遍就会新创建一个该对象,单例就失去了意义
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    if (manager == nil) {
        manager = [super allocWithZone:zone];
    }
    return manager;
}

通知

最熟悉的观察者模式

  • 观察者和被观察者都无需知晓对方,只需要通过标记在NSNotificationCenter中找到监听该通知所对应的类,从而调用该类的方法。
  • 并且在NSNotificationCenter中,观察者可以只订阅某一特定的通知,并对其做出相应,而不用对某一个类发的所有通知都进行更新操作。
  • NSNotificationCenter对观察者的调用不是随机的,而是遵循注册顺序一一执行的,并且在该线程内是同步的。

通知的具体使用步骤:

  1. 创建通知对象
NSNotification *notice = [NSNotification notificationWithName:@"send" object:self userInfo:@{@"name":_renameTextField.text,@"pass":_repassTextField.text}];
  1. 通知中心发送通知
[[NSNotificationCenter defaultCenter] postNotification:notice];
  1. 注册通知 添加观察者来指定一个方法、名称和对象,接受到通知时执行这个指定的方法。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(recive:) name:@"send" object:nil];
  1. 接受通知后调用的方法
- (void)recive:(NSNotification *)notice {
    NSDictionary *dictionary = notice.userInfo;
    _nameTextField.text = dictionary[@"name"];
    _passTextField.text = dictionary[@"pass"];
}

总结一下通知的用法:

  • 接收通知的类注册监听者并实现接收通知的事件函数
  • 触发通知的类在适当的时候发送通知

代理

又称委托代理,是iOS中常用的一种设计模式

协议,是多个类共享的一个方法列表,在协议中所列出的方法没有响应的实现,由其它类来实现。

委托是指给一个对象提供机会对另一对象中的变化做出反应或者相应另一个对象的行为。其基本思想是协同解决问题。

从方法的定义我们不难看出委托模式能够起到两方面的作用:

第一:代理协助对象主体完成某项操作,将需要定制化的操作通过代理来自定义实现,达到和子类化对象主体同样的作用。

第二:事件监听,代理对象监听对象主体的某些重要事件,对事件做出具体响应或广播事件交给需要作出响应的对象。
关于协议传值和属性传值

总结

KVO\KVC\单例模式\通知\代理\Block

KVO/通知 -------> 观察者模式
KVC --------> KVC模式
单例模式
代理模式

1. 代理和通知的区别

效率:代理比通知高;
关联:delegate是强关联,委托和代理双方互相知道。通知是弱关联,不需要知道是谁发,也不需要知道是谁接收。
代理是一对一的关系,通知是一对多的关系。delegate一般是行为需要别人来完成。通知是全局通知。
代理要实现对多个类发出消息可以通过将代理者添加入集合类后遍历,或通过消息转发来实现。

2. KVO和通知的区别

相同:都是一对多的关系;
不同:通知是需要被观察者先主动发出通知,观察者注册监听再响应,比KVO多了发送通知这一步。
监听范围:KVO是监听一个值的变化。通知不局限于监听属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,使用更灵活。
使用场景:KVO的一般使用场景是监听数据变化,通知是全局通知。

3. block和代理的区别

相同点:block代理都是回调的方式。使用场景相同。

不同点:

  • block集中代码块,而代理分散代码块。所以block更适用于轻便、简单的回调,如网络传输。 代理适用于公共接口较多的情况,这样做也更易于解耦代码架构。
  • block运行成本高。block出栈时,需要将使用的数据从栈内存拷贝到堆内存。当然如果是对象就是加计数,使用完或block置为nil后才消除。 代理只是保存了一个对象指针,直接回调,并没有额外消耗。相对C的函数指针,只是多做了一个查表动作。

4. 单例的优缺点

优点:

1:一个类只被实例化一次,提供了对唯一实例的受控访问。
2:节省系统资源
3:允许可变数目的实例。

缺点:

1:一个类只有一个对象,可能造成费任过重,在一定程度上违背了“单一职费原则”。
2:由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
3:滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会 导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。文章来源地址https://www.toymoban.com/news/detail-616736.html

到了这里,关于【iOS】单例、通知、代理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android,ios,安卓app推送消息通知,java后台向手机推送app的通知教程

    个推是商用级的移动应用消息推送云服务供应商,客户端 SDK 支持 Android 和 iOS 两大平台,开发者集成 SDK 后,可以通过个推强大的 web 端及丰富的 API 开放接口,发送推送消息、统计分析推送效果。可有效提高 App 活跃度,增加用户留存率。 如果您还没有个推 账号,可在 个推

    2024年02月04日
    浏览(32)
  • iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动

    iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动 在之前的开发中,遇到了实时音视频呼叫通知,当App未打开或者App在后台时候,需要通知到用户,用户点击通知栏后是否接入实时音视频的视频或者音频通话。 在iOS需要为工程新建Target:NotificationServiceExtensi

    2024年02月14日
    浏览(36)
  • macos编译libtiff库给IOS用

         

    2024年02月12日
    浏览(32)
  • 如何实现IOS APP被杀掉后依然可以接收到个推消息通知

    项目已经集成了个推SDK,但是在离线场景下无法收到推送消息,离线场景主要分2种情况,一种是用户将APP切换到了后台,一种是用户将APP杀掉了。 针对场景一:我们可以将APP支持后台运行,比如项目中使用到了后台持续定位功能,后台音频等(Xcode中可以查看支持哪些后台模

    2024年01月22日
    浏览(26)
  • iRemovalPro完美解4G信号,可以登录iCloud,有消息通知,支持IOS12-163。

    iRemovalPro是一款iOS12-16.3系统绕过激活锁界面的解锁工具,可以激活所有IPAD/苹果手机二网/三网恢复信号,并且支持插卡接打电话、收发短信、4G流量上网,支持iCloud登录,有消息通知,支持iPhone6~X的所有型号,支持最新iOS16.3,支持Windows10以上系统使用。 官方售价: iPhone 6s

    2024年02月04日
    浏览(36)
  • iOS/macOS - 逐行写入文件 (NSFileHandle)

    2024年02月15日
    浏览(34)
  • Charles证书过期解决方法macos/ios

    今天心血来潮打开Charles想试试看抓包手机APP(ios),结果发现各种x和提示ssl错误。开始以为是和魔法的代理冲突或者ip变了,捯饬很久后发现web的也报错。 然后搜了一会原因发现时证书过期了 1、搜索“钥匙串访问”,直接搜索“charles”,找到打叉的名称,直接删掉 2、打开

    2024年02月03日
    浏览(44)
  • MacOS 14 系统 XCode15、 Flutter 开发 IOS

    MacOS14 Sonoma 安装 Flutter 开发环境 MacOS 系统 Flutter开发Android 环境配置 MacOS 系统 Flutter开发IOS 环境配置​​​​​​​ 前面我们已经在MacOS14 M3芯片上安装好 Flutter环境,包括开发工具 VsCode 、Android Stuiod,那么flutter如何开发IOS呢? 我们知道IOS开发语言为 objcet-c或者 swift,Flutter是

    2024年02月03日
    浏览(55)
  • macOS Sonoma编译OpenCV源码输出IOS平台库

    1.macOS下载并编译OpenCV源码:  克隆源码: 主仓: git clone https://github.com/opencv/opencv.git 扩展仓:  git clone https://github.com/opencv/opencv_contrib.git    编译xcode源码需要CMake与XCode命令行工具 确认已安装CMake  确认已安装XCode  安装xcode command line tools 确认系统已安装python环境

    2024年02月10日
    浏览(47)
  • IOS设置系统代理+APP不走代理绕过方式

    确保手机和pc端网络连接同一个网络 1、设置burp端 2、手机进行代理设置   3、手机端访问代理,点击右上角下载burp证书,点击允许    点击已下载描述文件,选择安装  安装成功  4、通用--关于本机--证书信任设置,勾选我们已经安装的证书  5、然后就能抓到数据包啦 关闭

    2024年02月09日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包