@dynamic 模拟NSManagedObject类的内部实现,AFN的非常规用法
@property和@synthesize复习
@property生成setter和getter的声明,同时生成属性对应的成员变量,并且前面加一个下划线_。如果将getter和setter的实现同时重写之后,它不会帮助生成属性对应的变量名。 (TestOne.m)这种写法,无法编译通过,因为_name已经不存在。
@interface TestOne : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation TestOne
- (void)setName:(NSString *)name {
    _name = name; // Use of undeclared identifier '_name'
}
- (NSString *)name {
    return _name; // Use of undeclared identifier '_name'
}
@end
比较特殊的一种情况是readonly的属性只会帮助生成getter的声明和变量。,如果当getter被重写之后,成员变量也不存在。
@interface TestTwo : NSObject
@property (readonly, nonatomic, copy) NSString *name;
@end
@implementation TestTwo
- (NSString *)name {
    return _name; // Use of undeclared identifier '_name'
}
@end
如果在.h使用@property声明了方法属性,又想在.m重写方法怎么办呢。通常我们会使用@synthesize.
@synthesize是按照系统默认规则帮助生成getter和setter的实现,同时生成一个紧跟在关键字@synthesize后面的属性对应的成员变量,还可以更改属性对应的成员变量的名字。
同时如果使用了@synthesize之后,还可以继续重写getter和setter的实现,同时它帮助生成的成员变量依然存在。下面的代码是没有任何问题的。
@interface TestThree : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation TestThree
@synthesize name = _name; // 使用 @synthesize name 生成的成员变量是'name'
- (void)setName:(NSString *)name {
    _name = name;
}
- (NSString *)name {
    return _name;
}
@end
这时候@property的作用仅仅是相当于对外声明了方法原型:
- (void)setName:(NSString *)name;
- (NSString *)name;
但是不可以将.h中的@property (nonatomic, copy) NSString *name;替换为上面两句方法声明,因为@synthesize使用的前提是使用@property声明过这个属性。
对于readonly的属性,同样可以使用@synthesize关键字找到属性对应的成员变量名,然后重写getter就没有问题了。
@dynamic
我们都知道对应@dynamic修饰的属性,需要手动实现这个属性的getter和setter,否则虽然编译阶段能够通过,但是运行时会造成崩溃,错误信息为没有指定的方法。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。
例如下面的代码
@interface TestFour : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation TestFour
@dynamic name;
@end
// 在main.m中
TestFour *testFour = [[TestFour alloc] init];
testFour.name = @"Mike"; //已经奔溃 [TestFour setName:]: unrecognized selector sent to instance
NSLog(@"%@", testFour.name);
这里就体现出了@synthesize和@dynamic的区别:
@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法的实现。
@dynamic告诉编译器,属性的setter与getter方法需要实现,但是不会自动帮助生成。(当然对于readonly的属性只需提供getter实现即可)
@dynamic最常用的使用是在NSManagedObject中,此时不需要显示编程setter和getter方法。原因是:其getter和setter方法会在运行时动态创建,由Core Data框架为此类属性生成存取方法。那么CoreData究竟如何帮助NSManagedObject的子类生成子类属性的getter和setter实现的呢。我们大体可以模拟一下这个过程:
模拟CoreData NSManagedObject类的底层实现
根据OC运行时的特性,当子类的方法没有实现的实现,会去寻找父类的方法实现,为了语义上更好理解我使用Person和它的父类Super用来测试:(这其中Person模拟的是NSManagedObject的子类)
@interface Person : Super
@property (nonatomic, copy) NSString *name;
@end
@implementation Person
@dynamic name;
@end
@interface Super : NSObject
@end
@implementation Super
- (void)setName:(NSString *)name {
    NSLog(@"执行了Super的setName:");
    // setName ....
}
- (NSString *)name {
    NSLog(@"执行了Super的name");
    return @"Mike在Super中设置";
}
@end
Person *person = [[Person alloc] init];
person.name = @"Mike";
NSLog(@"%@", person.name);
因此上面的程序执行结果为:
执行了Super的setName:
执行了Super的name
Mike在Super中设置
那么问题就来了NSManagedObject是如何截获它子类的所有属性的getter和setter方法的调用,并完成代码实现的,毕竟它不会傻乎乎地把所有的属性都写一个getter和setter方法吧。虽然不知道它的具体实现方法,但是可以模拟一下这个过程。
这里提供一种利用消息转发机制来实现,主要用到两个方法- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector和- (void)forwardInvocation:(NSInvocation *)anInvocation:
methodSignatureForSelector:方法用来返回参数指定的SEL的指定的方法签名(方法签名是各种编程语言中通用的概念,主要是对方法的返回值类型、参数类型和参数的个数的描述,函数重载的概念就是同名方法具有不同的方法签名)。对于- (void)setName:(NSString *)name方法的方法签名就是:返回值为void类型参数个数为1参数类型为NSString。用自然语言描述是这样,如果用OC的方法编码描述就是:@"v@												
@dynamic 模拟NSManagedObject类的内部实现,AFN的非常规用法的更多相关文章
- Android线程管理(三)——Thread类的内部原理、休眠及唤醒
		
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...
 - Android线程管理(三)——Thread类的内部原理、休眠及唤醒
		
线程通信.ActivityThread及Thread类是理解Android线程管理的关键. 线程,作为CPU调度资源的基本单位,在Android等针对嵌入式设备的操作系统中,有着非常重要和基础的作用. ...
 - ulua  c#调用lua中模拟的类成员函数
		
项目使用ulua,我神烦这个东西.lua单纯在lua环境使用还好,一旦要跟外界交互,各种月经不调就来了.要记住贼多的细节,你才能稍微处理好.一个破栈,pop来push去,位置一会在-1,一会在-3,2 ...
 - C++ 模板的编译 以及 类模板内部的实例化
		
在C++中.编译器在看到模板的定义的时候.并不马上产生代码,仅仅有在看到用到模板时,比方调用了模板函数 或者 定义了类模板的 对象的时候.编译器才产生特定类型的代码. 一般而言,在调用函数的时候,仅仅 ...
 - 模拟窗口类ModelForm的应用
		
模拟窗口类ModelForm的应用 模拟窗口是Form的窗口中的fields是引用models类 不知道窗口类,点击:https://www.cnblogs.com/guguobao/p/932202 ...
 - 复习python的多态,类的内部权限调用 整理
		
#多态的用法 class Dii: passclass Aii(Dii): def run(self): print('一号函数已调用')class Bii(Dii): def run(Dii): p ...
 - 自定义异常类;键盘输入;try catch用法
		
相关考点:自定义异常类:键盘输入:try catch用法 1.设计一个java程序,自定义一个异常类,从键盘输入一个字符串,如果等于“abc”,则抛出异常. public class MyExcept ...
 - python类的内部方法
		
目录 一.绑定方法与非绑定方法 1.绑定方法 2.非绑定方法 二.property 1.什么是property? 2.为什么要用property? 3.如何使用property? 三.isinstan ...
 - 利用反射模拟一个spring的内部工作原理
		
这个简单的案例是实行了登录和注册的功能,没有链接数据库. 在bean中id 是唯一的,id和name的区别在于id不能用特殊字符而name可以用特殊字符,比如:/-\.... package com ...
 
随机推荐
- 修改组策略,禁止用户修改IP
			
运行中打开gepdit.msc,依次打开用户配置,管理模板,网络,网络连接:在右侧将“禁止访问LAN链接组建的属性”.“为管理员启用windows2000网络连接设置”设置为已启用即可令用户无法访问网 ...
 - JSP复习整理(一)表单
			
好久没更了,一周完成了SRDP,一周完成了课程设计,这一周就要好好回顾回顾Java Web的学习轨迹了. 用的eclipse Mars 一.表单 start.jsp <%@ page langu ...
 - POJ 2533 Longest Ordered Subsequence  LCS O(n*log(n))
			
题目链接 最长上升子序列O(n*log(n))的做法,只能用于求长度不能求序列. #include <iostream> #define SIZE 1001 using namespace ...
 - apk反编译工具
			
反编译工具: apktool:资源文件获取,可以提取出图片文件和布局文件进行使用查看 dex2jar:将apk反编译成Java源码(classes.dex转化成jar文件) jd-gui:查看APK中 ...
 - SSM框架总结(1)
			
----------------------20170106-------------------------------------- 1.mabatis.genertor中自动生成文件,需要在ge ...
 - GroupJoin和Join的声明及调用
			
public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable& ...
 - 修改MySql 数据默认存储路径
			
1. cmd进入控制台 net stop mysql 2.复制原来数据库目录到新目录 复制C:\ProgramData\MySQL\MySQL Server 5.5\中的data目录到 D:\Prog ...
 - wamp2.5 配置多端口虚拟主机
			
1.保证httpd.conf下 Include conf/extra/httpd-vhosts.conf LoadModule php5_module "D:/E/php/wamp/bin/ ...
 - C#winForm调用WebService的远程接口
			
Web Service 的创建简单编码.发布和部署 上一篇详细概述了WebService的创建,编码,发布和部署,那么作为客户端的程序如何访问远程端的WebService 接下来看一下具体步骤: ...
 - 防止sql注入和sqlmap介绍
			
sql注入问题从WEB诞生到现在也一直没停过,各种大小公司都出现过sql注入问题,导致被拖库,然后存在社工库撞库等一系列影响. 防止sql注入个人理解最主要的就一点,那就是变量全部参数化,能根本的解决 ...