【iOS】单例、通知、代理

单例\通知\代理

  • 单例模式
    • 什么是单例模式?
    • 单例模式的优缺点
      • 优点:
      • 缺点:
    • 实现方式
      • 懒汉式:
      • 饿汉式:
  • 通知
  • 代理
  • 总结
    • KVO\KVC\单例模式\通知\代理\Block

单例模式

什么是单例模式?

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

单例模式的优缺点

优点:

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

缺点:

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

实现方式

懒汉式:

实现原理和懒加载很想,如果在程序中不适用这个对象,那么就不会创建,只有在你使用代码创建这个对象,才会创建。这种思想在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:滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会 导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

本地非文字资源无法加载

目录 方法A.静态/动态绑定路径 方法B.require导入(运行时加载) 方法C.import导入(x)(编译时加载) 方法D.ref直接操作元素赋值(x) 相关知识 import和requir区别 模板路径&#…

华为华三思科 交换机基础配置一览

console密码修改 华为 user-interface console 0 authentication-mode password set authentication password cipher XXXXXXXXX华三 line aux 0 authentication-mode password set auth pass simple XXX思科 en configure terminal line console 0 password 123 login忘记…

❤️创意网页:打造炫酷网页 - 旋转彩虹背景中的星星动画

✨博主:命运之光 🌸专栏:Python星辰秘典 🐳专栏:web开发(简单好用又好看) ❤️专栏:Java经典程序设计 ☀️博主的其他文章:点击进入博主的主页 前言:欢迎踏入…

【C++ 进阶】学习导论:C/C++ 进阶学习路线、大纲与目标

目录 一、C 学习路线 二、C 课程大纲与学习目标 (1)第一阶段:C 语言基础 (2)第二阶段:C 高级编程 (3)第三阶段:C 核心编程与桌面应用开发 (4&#xf…

OAuth机制_web站点接入微软azure账号进行三方登录

文章目录 ⭐前言⭐微软三方登录流程💖 web站点获取微软账号流程💖 node封装微软登录接口💖 webapp 自定义code换token💖 调用 Microsoft Graph API💖 前端唤醒authlink进行登录回调逻辑 ⭐结束 ⭐前言 大家好&#xf…

深度学习论文: Q-YOLO: Efficient Inference for Real-time Object Detection及其PyTorch实现

深度学习论文: Q-YOLO: Efficient Inference for Real-time Object Detection及其PyTorch实现 Q-YOLO: Efficient Inference for Real-time Object Detection PDF: https://arxiv.org/pdf/2307.04816.pdf PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代…

【论文笔记】神经网络压缩调研

神经网络压缩调研 背景现有的深度模型压缩方法NetWork Prunning 网络剪枝设计结构化矩阵知识蒸馏权值共享Parameter Quantization(参数量化)量化和二进制化伪量化Architecture Design(Depth Separable Convolution)分解卷积 背景 …

matlab Tabel操作

https://zhuanlan.zhihu.com/p/104266351 Table数据类型的引用要三点要注意: 1){}–花括号(curly braces),()–小括号(parentheses), .–圆点(dot)对Table类型数据的作用…

Qt实现思维导图锦集

序号简述文章导航1思维导图树形结构、不重叠且均匀分布、支持折叠和展开核心树2菜单按钮风格、菜单提示风格、侧滑菜单、侧滑功能窗口UI设计3支持JPEG、PNG、XML、JSON、PDF、SVG格式文件数据导入导出4支持撤销回撤功能、显示节点操作流程、点击可跳转历史撤销回撤5思维导图横向…

AB 压力测试

服务器配置 阿里云Ubuntu 64位 CPU1 核 内存2 GB 公网带宽1 Mbps ab -c100 -n1000 http://127.0.0.1:9501/ -n:在测试会话中所执行的请求个数。默认时,仅执行一个请求。 -c:一次产生的请求个数。默认是一次一个。 ab -c 100 -n 200 ht…

opencv-25 图像几何变换04- 透视 cv2.warpPerspective()

什么是透视? 透视是一种几何学概念,用于描述在三维空间中观察物体时,由于视角的不同而产生的变形效果。在现实世界中,当我们从不同的角度或位置观察物体时,它们会呈现出不同的形状和大小。这种现象被称为透视效果。 透…

list与sort()

运行代码: //list与sort() #include"std_lib_facilities.h" //声明Item类 struct Item {string name;int iid;double value;Item():name(" "),iid(0),value(0.0){}Item(string ss,int ii,double vv):name(ss),iid(ii),value(vv){}friend istre…

【计网】TCP在可靠传输中都干了啥

文章目录 1、概述2、校验和3、序列号和确认应答机制4、重传机制4.1、介绍4.2、超时重传4.3、快速重传 5、滑动窗口协议5.1、介绍5.2、发送方的滑动窗口5.3、接收方的滑动窗口 6、流量控制7、拥塞控制7.1、介绍7.2、慢开始7.3、拥塞避免7.4、快重传和快恢复 1、概述 TCP 是面向…

lib-flexible修改配置适配更多不同分辨率

找到设置宽度的地方 然后根据你的屏幕最大多大呀&#xff0c;最小多小呀设置一下 if (width / dpr < 1980) { width 1980 * dpr; } else if (width / dpr > 5760) { width 5760 * dpr; }

https://app.hackthebox.com/machines/Sau

https://app.hackthebox.com/machines/Sau https://app.hackthebox.com/machines/Sau1.info collecting └─$ nmap -A 10.10.11.224 -T4 Starting Nmap 7.93 ( https://nmap.org ) at 2023-07-30 15:36 HKT Nmap scan report for 10.10.11.224 (10.10.11.224) Host is up (…

全局ip代理安全吗? 手机设置全局代理方法详解

全局IP代理并不一定是安全的&#xff0c;因为全局IP代理会将所有网络流量都通过代理服务器进行转发&#xff0c;包括敏感信息和隐私数据。如果代理服务器受到黑客攻击或存在安全漏洞&#xff0c;可能会导致数据泄露和其他安全问题。因此&#xff0c;在使用全局IP代理时&#xf…

Spring Boot实践四 --集中式缓存Redis

随着时间的积累&#xff0c;应用的使用用户不断增加&#xff0c;数据规模也越来越大&#xff0c;往往数据库查询操作会成为影响用户使用体验的瓶颈&#xff0c;此时使用缓存往往是解决这一问题非常好的手段之一。Spring 3开始提供了强大的基于注解的缓存支持&#xff0c;可以通…

【Leetcode】62.不同路径

一、题目 1、题目描述 一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径? 示例1: 输入:m = 3, n = 7 输出:…

AD21原理图的高级应用(六)原理图设计片段的使用

&#xff08;六&#xff09;原理图设计片段的使用 Altium Designer 的片段功能可以很方便地重复使用一些单元模块,其中包括原理图的电路模块、PCB(包括布线)和代码模块。例如在工程中需要设计电源模块,而别的工程中又恰好有比较完善的电源模块,这时就可以通过片段功能重复地使用…

京东技术专家首推:Spring 微服务架构设计,GitHub 星标 128K

前言 本书提供了实现大型响应式微服务的实用方法和指导原则&#xff0c;并通过示例全面 讲解如何构建微服务。本书深入介绍了 Spring Boot、Spring Cloud、 Docker、Mesos 和 Marathon&#xff0c;还会教授如何用 Spring Boot 部署自治服务&#xff0c;而 无须使用重量级应用服…