本文讨论的是,对于类中声明为 readonly 的属性值,我们就不可以修改其值了么?如何可以,那么如何修改呢?

为了便于说明,定义一个 ACLStudent 的类:

ACLStudent.h

@interface ACLStudent : NSObject

@property (nonatomic, assign, readonly) NSInteger studentId;
@property (nonatomic, copy, readonly) NSString *firstName;
@property (nonatomic, copy, readonly) NSString *lastName; - (instancetype)initWithStudentId:(NSInteger)studentId firstName:(NSString *)firstName lastName:(NSString *)lastName; @end -------------------------- ACLStudent.m @implementation ACLStudent - (instancetype)initWithStudentId:(NSInteger)studentId firstName:(NSString *)firstName lastName:(NSString *)lastName {
self = [super init];
if (self) {
_studentId = studentId;
_firstName = [firstName copy];
_lastName = [lastName copy];
} return self;
} @end 接下来定义一个 ACLStudent 类的对象: ACLStudent *student = [[ACLStudent alloc] initWithStudentId:1 firstName:@"Carya" lastName:@"Liu"];
NSLog(@"student firstName: %@", student.firstName); 现在我们考虑的就是如何修改 student 对象的 firstName 属性值为 @"Qiu" 。 如果直接调用 firstName 的 setter 方法, student.firstName = @"Qiu" , 那么就直接报错,提示不能够给声明为 readonly 的属性赋值。那么使用 KVC 呢? [student setValue:@"Qiu" forKey:NSStringFromSelector(@selector(firstName))];
NSLog(@"student firstName after changed: %@", student.firstName); 运行,发现属性值被成功修改。哈哈,那么现在来看看 KVC 为什么能够修改该属性值呢?看看文档 Accessor Search Implementation Details 。 当使用 setValue:forKey: 来设置对象的属性时,会以下面的优先顺序来寻找对应的 key : 消息接收对象会查找是否存在满足 set<Key>: 格式的存取方法。
如果不存在满足条件的存取方法,且消息接收对象的类方法 + (BOOL)accessInstanceVariablesDirectly 返回 YES,那么该对象会以 _<key> , _is<Key> , <key> , is<Key> 的顺序查找是否存在对应的key。
如果存在对应的存取方法或者找到对应的实例变量,那么就会改变该 key 所对应的值 value。必要的话,value 所对应的值会从对象中解析出来,如 Representing Non-Object Values 所描述的那样。
如果没有找到对应的存取方法或者实例变量,那么该消息对象的 setValue:forUndefinedKey: 将会调用。 对于上述第2点说明一下,如果我们不想让 setValue:forKey: 方法改变对象的属性值,那么重写其类方法 + (BOOL)accessInstanceVariablesDirectly 返回 NO (该方法默认返回 YES,即在不存在满足条件的存取方法时,允许直接访问属性对应的实例变量);在搜索实例变量时,会首先检查带下划线的实例变量,然后检查不带下划线的实例变量。 对于上述第3点举例说明,如果修改 student 对象的属性 NSInteger studentId , 注意其是 NSInteger 类型,我们在调用 setValue:forKey: 方法时可以像这样 [student setValue:@(20) forKey:NSStringFromSelector(@selector(studentId))]; 传入一个 NSNumber 对象也可以,Objective-C 会处理好一切。 对于上面的示例,使用 setValue:forKey: 实际修改的是 student 实例中 _firstName 实例变量的值。不要忘记,我们在声明一个 firstName 的属性时,编译器会为我们自动合成一个 _firstName 的实例变量。 总结: 当我们声明一个 readonly 的属性,外部可能会通过 KVC 修改该属性值。
为了避免 KVC 修改属性值,须将定义属性所在类的类方法 + (BOOL)accessInstanceVariablesDirectly 重写,使其返回 NO.

iOS修改声明为readonly的属性值的更多相关文章

  1. jquery attr()方法 添加,修改,获取对象的属性值。

    jquery attr()方法 添加,修改,获取对象的属性值. jquery中用attr()方法来获取和设置元素属性,attr是attribute(属性)的缩写,在jQuery DOM操作中会经常用到 ...

  2. 【iOS】Quartz2D练习-动态改变属性值

    一.通过slider控制圆的缩放 1.实现过程 新建一个项目,新建一个继承自UIview的类,并和storyboard中自定义的view进行关联.代码示例:SLViewController.m文件 # ...

  3. JQuery 操作对象的属性值

    通过JQuery去操作前台对象(div,span...)的属性是很常见的事情,本文就简单的介绍几种操作情形. 1):通过属性值去获取对象 2):用JQuery去修改对象的属性值 3):获取并修改对象的 ...

  4. CSS学习(7)继承、属性值的计算过程

    子元素会继承父元素的某些css属性 通常跟字体相关的属性都能被继承,具体的可以在mdn里查询是否是可继承属性 属性值的计算过程(渲染过程) 按照页面文档的树形目录结构进行依次渲染 前提条件:渲染的元素 ...

  5. 关于Javascript中通过实例对象修改原型对象属性值的问题

    Javascript中的数据值有两大类:基本类型的数据值和引用类型的数据值. 基本类型的数据值有5种:null.undefined.number.boolean和string. 引用类型的数据值往大的 ...

  6. tween.js是一款可生成平滑动画效果的js动画库。tween.js允许你以平滑的方式修改元素的属性值。它可以通过设置生成各种类似CSS3的动画效果。

    简要教程 tween.js是一款可生成平滑动画效果的js动画库.相关的动画库插件还有:snabbt.js 强大的jQuery动画库插件和Tweene-超级强大的jQuery动画代理插件. tween. ...

  7. dom4j修改,获取,增加xml中某个元素的属性值

    XML文件: <?xml version="1.0" encoding="UTF-8"?> <vrvscript> <item I ...

  8. 使用SetWindowPos API函数移动窗口后,还需修改Delphi的属性值,以备下次使用,否则就会出问题(不是API不起作用,而是使用了错误的坐标值)

    单独改变坐标的代码如下,可不断左移: procedure TForm1.Button1Click(Sender: TObject); begin SetWindowPos(panel1.Handle, ...

  9. iOS 将对象的属性和属性值拆分成key、value,通过字符串key来获取该属性的值

    这篇博客光看标题或许就会产生疑问,某个对象,只要它存在某个属性,且值不是空的,不就能直接用点方法获取吗,为什么要拆分成key和value多此一举呢?下面,我用一个例子告诉大家,既然这方法是存在的,那就 ...

随机推荐

  1. 修改Oracle 表空间名称 tablespace name

    修改表空间名称步骤如下: 1. 使用oracle用户登录执行 $sqlplus / as sysdba 2. 执行修改表空间命令如下 SQL> alter tablespace  TEST re ...

  2. Geodesic-based robust blind watermarking method for three-dimensional mesh animation by using mesh segmentation and vertex trajectory

    之前因为考试,中断了实验室的工作,现在结束考试了,不能再荒废了. 最近看了一篇关于序列水印的文章,大体思想是:对于一个网格序列,首先对第一帧进行处理,在第一帧上,用网格分割算法(SDF)将网格分割成几 ...

  3. 45度地图遮挡问题解决方案(cocos2d-x)

    最近一直在做45度斜视角游戏,也就是isometric等容地图,俗称2.5D.地图上物体的前后遮挡是我遇到的第一个问题,总结一下处理方法. 遮挡问题(不知道术语),就是比如一个角色站在树后面,那么树要 ...

  4. Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)

    [题目链接] http://www.tsinsen.com/A1219 [题意] 给定一棵树,a[u][i]代表u结点分配i人的收益,可以随时改变a[u],查询(u,v)代表在u子树的所有节点,在u- ...

  5. lighttpd mod_status模块

    用过nginx的status可以查看服务器的状态,之后就想lighttpd有没有这样的模块呢 之后看下配置文件,真的有,然后就试下 第一步, "mod_auth" 把这个前面的#号 ...

  6. openstack分布式安装

    一. keystone安装笔记 初次接触openstack,在尝试过单机部署以后不是很满意,就开始着手分布式部署,主要是按照openstack官网上的安装教程来的,本人安装的是目前最新的 I 版. 以 ...

  7. RStudio Keyboard Shortcuts

    Console Description Windows & Linux Mac Move cursor to Console Ctrl+2 Ctrl+2 Clear console Ctrl+ ...

  8. redis高级实用特性

    1. 安全性 2. 主从复制 3. 事务处理 4. 持久化机制 5. 发布订阅消息 : 可以做一个消息系统 6. 虚拟内存的使用 一 . 安全性 设置客户端连接后进行任何其他指定前需要使用的密码 . ...

  9. 15个顶级Java多线程面试题及答案

    1)现在有T1.T2.T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行? 这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉.这个多线程问题比 ...

  10. 现代程序设计——homework-08

    写在前面 以下内容出自一个对C++只有一点点了解,几乎没有写过C++程序的人,理解上的一定会很不到位,请各位路过神牛多多指点. 博客内容为对 http://www.cnblogs.com/softwa ...