属性关键字

属性关键字

  • 深拷贝与浅拷贝
    • 类型
    • 各类对象深浅拷贝判断
    • 完全深拷贝的实现
  • 属性关键字
    • @property、@synthesize和@dynamic
    • 原子操作
    • 读写权限
    • 内存管理
    • strong 🆚 copy
  • 总结

深拷贝与浅拷贝

先前学习OC时已经对深浅拷贝进行了一次学习,这里进行一个复习总结和补充,具体参照博客深拷贝与浅拷贝。

类型

OC对象的拷贝形式分为深拷贝、浅拷贝,其中深拷贝又细分为单层深拷贝和完全深拷贝。

  • 浅拷贝:指针拷贝,复制新指针与原指针存到同一块内存区域。
  • 深拷贝:内容拷贝,将数据拷贝到一块新的内存区域,新指针指向新区域。
    • 单层深拷贝:副本对象本身是深拷贝,其里面所有对象是浅拷贝。(例如容器类数组对象本身是深拷贝,数组元素是浅拷贝)
    • 完全深拷贝:无论副本对象本身还是里面对象元素都是深拷贝。

各类对象深浅拷贝判断

  • 可变对象(非容器类、容器类)的copy和mutableCopy都为深拷贝。
  • 不可变对象(非容器类、容器类)的copy为浅拷贝,mutableCopy为深拷贝。
  • 自定义对象的copy和mutableCopy都为深拷贝。

无论容器类对象还是非容器类对象,都属于系统类,xCode会自动帮我们实现好copyWithZone:mutableCopyWithZone:方法。然而自定义类的这两个方法需要我们自己手动实现。

@implementation Person- (id)copyWithZone:(NSZone *)zone {Person *copy = [[[self class] allocWithZone:zone] init];copy.name = [self.name copy];copy.age = self.age;return copy;
}- (id)mutableCopyWithZone:(NSZone *)zone {Person *copy = [[[self class] allocWithZone:zone] init];copy.name = [self.name mutableCopy];copy.age = self.age;return copy;
}@end

从上述的方法实现中我们可以看出,无论是copy还是mutableCopy,这里都init出一个新的对象,开辟了一个新内存,与原对象不在一个内存地址,这就是深拷贝。

完全深拷贝的实现

在之前的博客中对完全深拷贝的实现没有过多讲解,这里具体总结一下从单层深拷贝转换为为完全深拷贝的两种方法。

  • 归档和解档

这种方法的重点在于实现encodeWithCoder:initWithCoder:方法。对于系统自带类来说,自动实现了这两个方法,可以直接归档和解档。相反,自定义类的归档和解档的关键就是遵守NSSecureCoding 协议实现以下方法:

#import "Person.h"@implementation Person//支持安全编码
+(BOOL)supportsSecureCoding {return YES;
}//将对象转化为二进制
- (void)encodeWithCoder:(nonnull NSCoder *)coder {[coder encodeObject:self.name forKey:@"name"];
}//二进制还原对象
- (instancetype)initWithCoder:(nonnull NSCoder *)coder {if (self = [super init]) {self.name = [coder decodeObjectOfClass:[NSString class] forKey:@"name"];}return self;
}@end
#import <Foundation/Foundation.h>
#import "Person.h"int main(int argc, const char * argv[]) {@autoreleasepool {Person *person = [[Person alloc] init];person.name = @"Alice";NSLog(@"%p---%@", person, person.name);//归档,将对象封装进二进制容器NSData *data = [NSKeyedArchiver archivedDataWithRootObject:person requiringSecureCoding:YES error:nil];//解档Person *copyPerson = [NSKeyedUnarchiver unarchivedObjectOfClass:[Person class] fromData:data error:nil];NSLog(@"%p---%@", copyPerson, copyPerson.name);person.name = @"Bob";NSLog(@"%p---%@", person, person.name);NSLog(@"%p---%@", copyPerson, copyPerson.name);}return 0;
}

运行结果:

在这里插入图片描述

从运行结果可以看出,通过解档归档,得到了一个新对象,新建了一块内存地址,内容相同但地址不同,因此是深拷贝。并且,修改原始对象不改变解档对象,二者彼此独立,所以copyPerson依然是原来的值,这也说明实现了深拷贝。

  • 使用initWithXxx: copyItems:YES方法

该方法只能实现一层深拷贝,因此只有当容器类对象中的对象是自定义类对象或者可变对象时,可以实现完全深拷贝。很好理解,因为自定义类对象和可变对象的拷贝都是深拷贝,因此使用该方法再实现一层深拷贝就实现了完全深拷贝。

#import <Foundation/Foundation.h>int main(int argc, const char * argv[]) {@autoreleasepool {NSMutableString *str1 = [NSMutableString stringWithString:@"Alice"];NSMutableString *str2 = [NSMutableString stringWithString:@"Bob"];NSArray *arr = @[str1, str2];NSArray *copyArr = [[NSArray alloc] initWithArray:arr copyItems:YES];NSLog(@"%@---%p", arr, arr);NSLog(@"%@---%p", copyArr, copyArr);NSLog(@"%@---%p", str1, str1);NSLog(@"%@---%p", copyArr[0], copyArr[0]);[str1 appendString:@"Tom"];NSLog(@"%@---%p", str1, str1);NSLog(@"%@---%p", copyArr[0], copyArr[0]);}return 0;
}

运行结果:

在这里插入图片描述

从运行结果可以看出,通过这种方法只复制了内容,但地址不同,并且对原对象的修改不会影响copyArr对象的内容。

值得注意的是:如果不是上述所说的容器类对象中的对象是自定义类对象或者可变对象时,使用该方法实现的是单层深拷贝。

属性关键字

  1. 属性的本质是 ivar(实例变量)+getter(getter方法)+setter(setter方法)。
  2. 属性的修饰符应该按照顺序排列:原子操作、读写权限、内存管理

@property、@synthesize和@dynamic

ivar+getter+setter的组合方式使得代码臃肿,因此使用@property、@synthesize和@dynamic来实现属性自动合成存取方法。

  • @property:用于封装对象中的数据,自动生成属性的setter与getter方法的声明。
  • @synthesize:自动生成setter和getter方法。
  • @dynamic:告诉编译器不自动进行@synthesize,而是程序员手动实现setter和getter方法。

注意⚠️:

  • 如果重写setter和getter方法,编译器就不会自动为@property生成@synthesize,需要手动添加。
  • 如果在协议里使用@property声明一个属性,那么在某个类中遵循这个协议时,@synthesize需要手动添加同时生成实例变量和setter和getter方法。
#import <Foundation/Foundation.h>@protocol Demand <NSObject>-(void)testDemand;
@property(nonatomic, strong) NSString *name;@end@interface Person : NSObject<NSSecureCoding>@end#import "Person.h"@implementation Person@synthesize name = _name;-(void)testDemand {NSLog(@"属性关键字");
}

原子操作

属性是否具有原子性可以理解为线程是否安全。

同步锁:在多线程环境中,当多个线程同时访问或修改同一对象时,会导致程序崩溃等结果。同步锁则是一种用于确保在给定时间内只有一个线程可以执行某特定代码而保证线程安全的机制。

  • atomic:原子性,加同步锁,但也不一定保证线程安全,且会损耗性能。
  • nonatomic:非原子性,不加同步锁,使用这个可以提高访问性能,代码中常用nonatomic修饰属性。

读写权限

  • readwrite:默认,生成setter和getter方法。
  • readonly:只生成getter方法。

内存管理

  • assign:
    • 既可以修饰基本数据类型(NSInteger、BOOL、int、float 等),也可以修饰对象类型。

      ps:如果使用assign修饰OC对象,对象销毁时可能会产生悬垂指针,从而出现程序崩溃,因此最好assign只用来修饰基本数据类型。

    • 一般对于基本数据类型,setter方法的实现可以是直接赋值。
    • 修饰对象类型时,不增加引用计数。
    • 修饰delegate 在MRC使用assign.
    • 会产生悬垂指针,assign修饰的对象在被释放后,指针仍然指向原对象地址,也就是说如果assign修饰的对象被释放后,仍通过该指针访问原对象的话,程序可能崩溃。

      悬垂指针:指针所指的内存已经被释放(对象已被销毁),但指针本身仍然存在,并继续指向那块现在已经无效的内存地址。

  • weak:
    • 只能修饰对象类型(只能修饰OC对象,如UIButton、UIView等)。
    • ARC下才能使用。

      ARC: 是一种编译器特性,它*编译时自动为你插入适当的内存管理代码(retain, release, autorelease),而不是像传统手动引用计数(MRC)那样需要开发者自己写这些代码。

    • 修饰弱引用,不增加引用计数,用于避免循环利用。
    • weak 修饰的对象在被释放之后,会自动将指针置为 nil,不会产生悬垂指针。
    • 对于有必要进行 remove 的视图可以使用 weak,remove 之后会自动置为 nil。
    • 修饰delegate 在ARC使用weak。
  • unsafe_unretained:
    • 既可以修饰基本数据类型,也可以修饰对象类型。
    • MRC 下经常使用,ARC 下基本不用。
    • 修饰弱引用,同 weak,但性能更好,同时使用要求高,因为会产生悬垂指针。
  • retain:
    • MRC下使用。
    • 修饰强引用,将指针原来指向的旧对象释放掉,然后指向新对象,同时新对象的引用计数加1。
    • setter 方法的实现是 release 旧值,retain 新值,用于OC对象类型。

strong 🆚 copy

  • strong:
    • ARC 下才能使用。
    • 原理同 retain,但在修饰 block 时,strong 相当于 copy,而 retain 相当于 assign。
    • 浅拷贝
  • copy:
    • setter 方法的实现是 release 旧值,copy 新值。一般用于 block、NSString、NSArray、NSDictionary 等类型。
    • copy设置的属性会复制传入的对象,而不是仅仅保持对传入对象的引用,用于确保属性拥有自己的独立副本,使得避免不经意的更改。
  • 区别:
    • 属性声明使用copy修饰,则合成方法使用类的copy方法,生成一个对象的不可变副本。
    • strong修饰的的对象的赋值是多个指针指向同一个地址,而copy对象的赋值是每次在内存中开辟一个新内存地址,指针指向不同的地址。
@interface Person : NSObject<NSSecureCoding>@property(nonatomic, strong) NSString *strStrong;
@property(nonatomic, copy) NSString *strCopy;
@property(nonatomic, strong) NSMutableString *mutablestrStrong;
@property(nonatomic, copy) NSMutableString *mutablestrCopy;-(void)testDemo;@end-(void)testDemo {NSMutableString *str = [NSMutableString stringWithString:@"Hello"];NSLog(@"%@---%p", str, str);self.strStrong = str;NSLog(@"%@---%p", self.strStrong, self.strStrong);self.strCopy = str;NSLog(@"%@---%p", self.strCopy, self.strCopy);self.mutablestrStrong = str;NSLog(@"%@---%p", self.mutablestrStrong, self.mutablestrStrong);self.mutablestrCopy = str;NSLog(@"%@---%p", self.mutablestrCopy, self.mutablestrCopy);[str appendString:@" iOS"];NSLog(@"%@---%p", self.strStrong, self.strStrong);NSLog(@"%@---%p", self.strCopy, self.strCopy);NSLog(@"%@---%p", self.mutablestrStrong, self.mutablestrStrong);NSLog(@"%@---%p", self.mutablestrCopy, self.mutablestrCopy);
}

运行结果:

在这里插入图片描述

从运行结果看的出,正如我们的结论所说,strong修饰的赋值指向同一个地址(浅拷贝),copy修饰的赋值指向新的地址(深拷贝)。因此,当原值改变时,strong修饰的对象的指针还指向原内存,因此值随之改变,而copy的不会改变。

因此,对于copy修饰的对象,为确保对象中的字符串值不会无意改动,应该在赋值前拷贝一份。

总结

属性关键字的知识还有很多,后续学习后会完善补充。

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

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

相关文章

突发奇想,还未实践,在Vben5的Antd模式下,将表单从「JS 配置化」改写成「模板可视化」形式(豆包版)

在 Vben5 的 Antd 模式下&#xff0c;完全可以将表单从「JS 配置化」改写成「模板可视化」形式&#xff0c;把表单项直接写在 Vue 模板中&#xff0c;更直观且符合传统 Vue 开发习惯。以下是完整的改写示例&#xff0c;保留原功能但结构更清晰&#xff1a; 改写思路 放弃 JS 中…

【更新完毕】2025数学建模国赛E题思路代码文章高教社杯全国大学生数学建模-AI 辅助智能体测

全部更新完毕 包含完整的文章全部问题的代码、结果、图表 完整内容请看文末最后的推广群基于AI姿态识别的立定跳远运动分析与个性化训练优化研究 随着《国家学生体质健康标准》的颁布实施&#xff0c;通过AI技术辅助体育运动分析已成为提升学生体质健康水平的重要手段。本研究针…

小白友好,无需基础也能快速上手的AI部署工具,一键部署

AI大模型相信已经成为许多人工作和生活中的得力助手。然而&#xff0c;对于大多数普通用户而言&#xff0c;将强大的AI模型部署到自己的电脑上&#xff0c;似乎是一项遥不可及的技术活&#xff0c;往往涉及到复杂的命令行操作、环境配置和代码调试。那有没有一种工具&#xff0…

《Python复刻植物大战僵尸开源项目实战:Pygame框架+JSON关卡设计,解锁塔防游戏开发新技能》​

&#x1f4cc; 大家好&#xff0c;我是智界工具库&#xff0c;每天分享好用实用且智能的开源项目&#xff0c;以及在JAVA语言开发中遇到的问题&#xff0c;如果本篇文章对您有所帮助&#xff0c;请帮我点个小赞小收藏小关注吧&#xff0c;谢谢喲&#xff01;&#x1f618; 博主…

CCS——将工程中的 include / lib 修改为相对路径,方便工程分享

在使用 Code Composer Studio (CCS) 开发 DSP 或 ARM 工程时&#xff0c;经常会遇到这样一个问题&#xff1a;在 A 电脑上能正常编译的工程&#xff0c;拷贝到 B 电脑上后就报错。错误的原因通常是 工程使用了绝对路径&#xff0c;而不同电脑上的文件路径不一致&#xff0c;比如…

java解析网络大端、小端解析方法

文章目录一、背景介绍二、说明核心概念&#xff1a;什么是字节序&#xff08;Endianness&#xff09;&#xff1f;大端字节序 (Big-Endian)小端字节序 (Little-Endian)三、不同解析方式介绍一、背景介绍 中转台通过SNMP协议V1\V2上报中转台IP&#xff0c;然后程序解析入库&…

【数据分享】土地利用矢量shp数据分享-甘肃

今天要说明数据就是土地利用shp数据分享-甘肃。数据介绍▲ 1km土地利用数据&#xff08;2020年&#xff09;▲ 土地利用数据&#xff08;2025年&#xff09;▲土地利用数据&#xff08;2018年&#xff09;▲ 30m土地利用数据&#xff08;2023年&#xff09;▲ 公路铁路道路河流…

java log相关:Log4J、Log4J2、LogBack,SLF4J

目录测试maven依赖logback.xml测试主程序测试输出arthas查看logger总结使用参考文档测试 maven依赖 <dependencies><!-- SLF4J API --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>…

AES加密算法详细加密步骤代码实现--身份证号码加解密系统

系统概述 本系统是一个基于AES-256-CBC加密算法的身份证号码加解密工具&#xff08;手搓底层步骤&#xff09;&#xff0c;针对的是上一篇文章对的AES加密原理的讲解&#xff0c;虽说是演示&#xff0c;但功能完善&#xff0c;可单独提供接口给项目调用&#xff0c;采用Python…

LangChain: Models, Prompts 模型和提示词

获取openapikey #!pip install python-dotenv #!pip install openai import osimport openai ​ from dotenv import load_dotenv, find_dotenv _ load_dotenv(find_dotenv()) # read local .env file openai.api_key os.environ[OPENAI_API_KEY] # account for deprecat…

ACMESSL自动续签教程

目录 1、选择申请证书 ​编辑2、选择CA机构 ​编辑3、选择自动验签 ​编辑4、证书续签设置 5、自动发布设置 本教程实现ACMESSL自动续签&#xff0c;请按照此教程实现。 1、选择申请证书 点击快捷入口或者订单或证书列表中的【创建证书】按钮&#xff1a; 2、选择CA机构 …

基于飞算JavaAI的在线图书借阅平台设计实现

项目概述与需求分析 1.1 项目背景与意义 随着数字化时代的快速发展&#xff0c;传统图书馆管理模式已无法满足现代读者的需求。在线图书借阅平台通过互联网技术将图书资源数字化&#xff0c;为读者提供便捷的检索、借阅和管理服务&#xff0c;有效解决了传统图书馆开放时间有…

通过API接口管理企业微信通讯录案例

1.开始前需要登录企业微信管理员后台&#xff0c;开启通讯录同步&#xff0c;同时添加企业可信IP地址&#xff0c;记录下Secret信息和企业ID&#xff0c;后面的程序会用到这两个参数。2.下面是用python写的创建企业微信账号的具体案例。#!/usr/bin/env python3 # -*- coding: u…

硬件开发_基于物联网的自动售卖机系统

一.系统概述 物联网自动售卖机系统的主要功能如下&#xff1a; 核心控制器&#xff1a;采用STM32单片机作为系统核心&#xff0c;负责整体数据处理和各设备的统一控制。商品选择&#xff1a;支持语音识别及按键方式&#xff0c;方便用户在售卖机内选择商品。语音播报&#xff1…

AGENTS.md: AI编码代理的开放标准

每个项目都有一个 README.md 文件供人类阅读。但随着 AI 编码代理和 AI 辅助开发的兴起,我们需要一个新标准:AGENTS.md。这个 Markdown 文件定义了代理如何构建、测试和协作。 这就是 AGENTS.md 的作用。 它是一个简单的 Markdown 文件,告诉 AI 助手如何在你的项目中操作:…

如何解决 OutOfMemoryError 内存溢出 —— 原因、定位与解决方案

网罗开发&#xff08;小红书、快手、视频号同名&#xff09;大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等方…

阿里云服务器配置ssl-docker nginx

# 切换到您当前的目录 cd /AAAAAAAAAAAA# 创建存放nginx配置、证书和日志的目录结构 mkdir -p nginx-config/conf.d nginx-ssl nginx-logs# 为挂载做准备&#xff0c;您可能需要将当前dist目录内容移动到新的html目录 # 首先查看当前dist目录的内容 ls -la dist/# 如果html目录…

2025全球生成式引擎优化(GEO)服务商发展趋势与企业赋能白皮书

引言&#xff1a;人工智能技术的迅猛发展&#xff0c;特别是在生成式AI领域的突破&#xff0c;正以前所未有的力量重塑商业世界的竞争格局。对于寻求提升在线可见性、优化品牌互动及实现可持续增长的企业而言&#xff0c;生成式引擎优化&#xff08;GEO&#xff09;已然成为数字…

海康威视工业相机SDK开发实战:使用C/C++实现软件触发图像采集(含详细中文注释代码)

一、前言 在机器视觉、自动化检测、智能制造等领域&#xff0c;工业相机是获取图像数据的核心设备。海康威视作为国内领先的机器视觉厂商&#xff0c;其工业相机产品线丰富&#xff0c;广泛应用于各类工业场景。 本文将带你从零开始&#xff0c;使用 海康MVS SDK&#xff08;Ma…

Modbus RTU 协议介绍

Modbus RTU 协议介绍 异步串行传输方式&#xff0c;采用二进制格式&#xff0c;适用于串行通讯&#xff08;如RS-485&#xff09;&#xff0c;效率高&#xff0c;是工业现场的主流选择。 主站是Master&#xff0c;从站是Slave。 Modbus RTU 协议格式 帧结构 地址码&#xf…