Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >KVC 使用方法详解及底层实现你要知道的KVC、KVO、Delegate、Notification都在这里

KVC 使用方法详解及底层实现你要知道的KVC、KVO、Delegate、Notification都在这里

作者头像
WWWWDotPNG
发布于 2018-04-10 03:45:14
发布于 2018-04-10 03:45:14
1.3K00
代码可运行
举报
文章被收录于专栏:iOS技术杂谈iOS技术杂谈
运行总次数:0
代码可运行

你要知道的KVC、KVO、Delegate、Notification都在这里

转载请注明出处 https://cloud.tencent.com/developer/user/1605429

本系列文章主要通过讲解KVC、KVO、Delegate、Notification的使用方法,来探讨KVO、Delegate、Notification的区别以及相关使用场景,本系列文章将分一下几篇文章进行讲解,读者可按需查阅。

  • KVC 使用方法详解及底层实现
  • KVO 正确使用姿势进阶及底层实现
  • Protocol与Delegate 使用方法详解
  • NSNotificationCenter 通知使用方法详解
  • KVO、Delegate、Notification 区别及相关使用场景

KVC使用方法详解与底层实现

KVC(key value coding)键值编码是一种可以使用字符串形式来间接操作对象相关属性的方法。KVC需要由类别Category NSKeyValueCoding来支持,OC在实现KVC时没有采用实现接口的方式,而是针对NSObject创建了一个类别,通过这样的方式使得NSObject的子类可以自行实现NSKeyValueCoding类别定义的相关方法。

KVC使用非常简单,但KVC却异常强大,最暗黑的功能就是它可以无视访问限制,无论是否为private都可以进行赋值或取值操作,readonly的属性也可以无视,提供了一种比runtime更便捷的方式来修改或访问系统级隐藏的属性,因此,经常在开发中通过runtime获取相关属性名后使用KVC来修改那些只读readonly或隐藏的属性。

KVC基础方法详解

KVC常用方法主要由如下几个:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//获取属性名为key的属性的值
- (nullable id)valueForKey:(NSString *)key;

//设置属性名为key的属性的值为value
- (void)setValue:(nullable id)value forKey:(NSString *)key;

/*
提供一种类似于Java ONGL语法来访问嵌套属性
获取嵌套属性名为keyPath的属性的值
*/
- (nullable id)valueForKeyPath:(NSString *)keyPath;

//设置嵌套属性名为keyPath的属性的值为value
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;

/*
获取属性名为key的属性值时,如果属性不存在则执行该方法,可自定义实现,
默认实现方式为抛出NSUnknownKeyException异常
*/
- (nullable id)valueForUndefinedKey:(NSString *)key;

/*
设置属性名为key的属性值为value时,如果属性不存在则执行该方法,可自定义实现,
默认实现方式为抛出NSUnknownKeyException异常
*/
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;

针对上述方法举一个栗子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//Phone类
@interface Phone : NSObject
@property (nonatomic, strong) NSString *phoneNumber;
@end

@implementation Phone
@synthesize phoneNumber = _phoneNumber;
@end

//Person类
@interface Person : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSUInteger age;
//组合一个Phone的对象
@property (nonatomic, strong) Phone *phone;
- (void)showMyself;

@end

@implementation Person

@synthesize name = _name;
@synthesize age = _age;
@synthesize phone = _phone;

- (void)showMyself {
    NSLog(@"My name is %@ I am %ld years old. my phone number is %@", self.name, self.age, self.phone.phoneNumber);
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Person *p = [[Person alloc] init];
        
        [p setValue:@"Jiaming Chen" forKey:@"name"];
        [p setValue:@22 forKey:@"age"];
        [p setValue:[[Phone alloc] init] forKey:@"phone"];
        [p setValue:@"18666668888" forKeyPath:@"phone.phoneNumber"];
        //输出: My name is Jiaming Chen I am 22 years old. my phone number is 18666668888
        [p showMyself];
        //输出: Name: Jiaming Chen
        NSLog(@"Name: %@", [p valueForKey:@"name"]);
        //输出: Age: 22
        NSLog(@"Age: %@", [p valueForKey:@"age"]);
        //输出: Phone Number: 18666668888
        NSLog(@"Phone Number: %@", [p valueForKeyPath:@"phone.phoneNumber"]);
    }
    return 0;
}

上面的栗子使用了setValue:forKeyvalueForKey:setValue:forKeyPathvalueForKeyPath方法。Person类组合了Phone类,因此在访问phone属性phoneNumber属性时,需要使用keyPath这样的字符串点语法,可以根据实际情况一直嵌套下去。这个栗子比较简单,不做过多赘述。接下来在看一个栗子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@interface Person : NSObject
{
    @private
    NSString *name;
    NSString *_name;
}

- (void)outputAddress;

@end

@implementation Person
{
    NSInteger age;
}

- (void)outputAddress
{
    NSLog(@"Address name: %p _name: %p", name, _name);
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Person *p = [[Person alloc] init];
        
        [p setValue:@"Jiaming Chen" forKey:@"name"];
        [p setValue:@"CCCC" forKey:@"_name"];
        [p setValue:@22 forKey:@"age"];
        
        //输出: Name: CCCC 0x1000010a8
        NSLog(@"Name: %@ %p", [p valueForKey:@"name"], [p valueForKey:@"name"]);
        //输出: _Name: CCCC 0x1000010a8
        NSLog(@"_Name: %@ %p", [p valueForKey:@"_name"], [p valueForKey:@"_name"]);
        //输出: Age: 22
        NSLog(@"Age: %@", [p valueForKey:@"age"]);
        //输出: Address name: 0x0 _name: 0x1000010a8
        [p outputAddress];

    }
    return 0;
}

为了展示实验效果这里没有使用合成存取方法,Person类声明的属性name_name以及age都是private的,但是KVC依旧可以为其设置值,同样的也可以获取private属性的值,这就是KVC的强大之处。

但似乎上面栗子的输出结果与我们预期不同,明明通过setValue:forKey:name属性设置的值是Jiaming Chen但通过valueForKey:输出的结果却与_name属性值一致,连输出的地址都一样。通过outputAddress方法输出name_name的地址后发现name的地址为0x0,这表示其并未初始化,出现这种情况的原因正是因为KVC获取值和赋值的顺序有关,由于篇幅问题,这里没有给出所有的实验过程,有兴趣的读者可以按照下述顺序自行实验,通过实验可得如下赋值顺序:

  • 首先通过setter方法即set(Key属性名):,这里是setName:方法进行赋值。
  • 如果没有setter方法,寻找_(key属性名),这里是_name成员变量,无视该成员变量的访问修饰符,也无视该成员变量是在@interface的类接口部分定义的还是在@implementation类实现部分定义的,只要存在该名称的成员变量就为其赋值。
  • 如果没有setter方法也没有_(key属性名),这里是_name成员变量,就会寻找key属性名,这里是name成员变量,同样无视其访问修饰符,无视其定义位置,只要存在该名称的成员变量就为其赋值。
  • 如果setter_(key属性名)key属性名都不存在则会调用setValue:forUndefinedKey:方法,该方法默认实现是抛出NSUnknownKeyException异常。

同样的,对于valueForKey:方法来获取值的顺序如下:

  • 首先通过getter方法来获取值,这里为name方法。
  • 如果没有getter方法则会查找名称为_(key属性名)这里为_name的成员变量,同样无视访问修饰符,无视定义位置,只要存在该成员变量就返回其值。
  • 如果没有getter方法也没有_(key属性名)成员变量,则查找名称为key属性值这里为name的成员变量,同样无视访问修饰符,无视定义位置,只要存在该成员变量就返回其值。
  • 如果getter_(key属性名)key属性名都不存在则会调用valueForKey方法,该方法默认实现是抛出NSUnknownKeyException方法。

当我们清楚的认识到上述KVC获取值和赋值的相关顺序后,也就理解了前一个栗子结果产生的原因,通过上面的讲解也可以发现其实KVC方法的效率并不高,KVC还是要去搜索gettersetter搜索各种成员变量,显然通过直接赋值或获取值效率更高,所以,在普通情况下尽量不要使用KVC这样的方式。

接下来再举一个在实际开发中常使用的栗子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#import <Foundation/Foundation.h>
//Person类
@interface Person : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSUInteger age;
//服务端为id,由于id是OC的关键字,取名为idNumber
@property (nonatomic, copy) NSString *idNumber;
- (void)showMyself;

@end

@implementation Person

@synthesize name = _name;
@synthesize age = _age;
@synthesize idNumber = _idNumber;

- (void)showMyself {
    NSLog(@"Name: %@ Age: %ld idNumber: %@", self.name, self.age, self.idNumber);
}

- (nullable id)valueForUndefinedKey:(NSString *)key
{
    return nil;
}

- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key
{
    //如果这个key为id
    if ([key isEqualToString:@"id"])
    {
        //调用setValue:forKey方法为idNumber赋值
        [self setValue:value forKey:@"idNumber"];
    }
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //假设为服务端获取的json数据转换的dictionary
        NSDictionary *dict = @{@"name": @"Jiaming Chen", @"age": @20, @"id": @"1603121434"};
        
        Person *p = [[Person alloc] init];
        //遍历上述字典的key
        [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
            //直接使用kvc赋值,不需要再写一行一行代码赋值
            [p setValue:obj forKey:key];
        }];
        //输出: Name: Jiaming Chen Age: 20 idNumber: 1603121434
        [p showMyself];
    }
    return 0;
}

上面的栗子在Person类中自定义实现了valueForUndefinedKey:setValue:forUndefinedKey:方法,如果不实现该方法设置不存在的key时默认抛出异常,在实际开发中通常需要从服务端获取大量的json数据,转换为字典后往往需要一个属性一个属性的赋值,使用KVC方法就能够避免编写冗长的代码,但有时服务端和客服端的数据名称会有不同,此时可以按情况在setValue:forUndefinedKey:方法中进行处理。

在实际开发中还遇到过一种情况,iOS端的对象使用NSString类型存储用户ID,但服务端返回的是int类型的数据,在赋值时就会崩溃,解决该问题需要我们自己实现setValue:forKey:方法,在该方法中判断value的类型后手动转换即可,在此不再赘述。

通过上面的栗子,如果需要使用KVC进行赋值操作,最好按照需求自定义实现valueForUndefinedKey:setValue:forUndefinedKey:以及setValue:forKey:方法。

KVC修改readonly的系统隐藏变量

首先上一张阿里云iOS端app的图,如下图所示:

阿里云iOS端首页

我们发现首页上方旋转木马的UIPageControl不是传统的圆形而是长条形,如果不使用自定义控件或是使用h5实现,那我们该如何实现这个效果呢?

首先我们使用如下代码创建一个UIPageControl:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (instancetype)init
{
    if (self=  [super init])
    {
        self.view.backgroundColor = [UIColor whiteColor];
        
        UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(0, 200, ScreenWidth, 200)];
        containerView.backgroundColor = [UIColor greenColor];
        [self.view addSubview:containerView];
        
        UIPageControl *pageControler = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 180, ScreenWidth, 20)];
        pageControler.numberOfPages = 4;
        [pageControler setPageIndicatorTintColor:[UIColor blueColor]];
        [pageControler setCurrentPageIndicatorTintColor:[UIColor blackColor]];
        [containerView addSubview:pageControler];       
    }
    return self;
}

实现效果如下图:

UIPageControl基本样式

首先查看UIPageControl提供给我们可访问的属性,看一下有没有可以操作的属性,这里可以自行查看,我们发现并没有这样的属性存在,这个时候该怎么办呢?接着我们可以使用runtimeUIPageControl的所有属性都打印出来,runtime的强大之处就在于可以获取类的任意属性和方法,关于runtime部分本博客有一系列文章来讲解,有兴趣的读者可以自行查阅iOS runtime探究(一): 从runtime开始理解面向对象的类到面向过程的结构体

我们先打印出UIPageControl所有属性,看一下有没有我们需要的,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
执行下述代码需要import <objc/runtime.h>头文件

unsigned int count = 0;
//该方法是C函数,获取所有属性
Ivar * ivars = class_copyIvarList([pageControler class], &count);
for (unsigned int i = 0; i < count; i ++) 
{
    Ivar ivar = ivars[i];
    //获取属性名
    const char * name = ivar_getName(ivar);
    //使用KVC直接获取相关属性的值
    NSObject *value = [pageControler valueForKey:[NSString stringWithUTF8String:name]];
    NSLog(@"%s %@", name, value);
}
//需要释放获取到的属性
free(ivars);

输出如下:

_lastUserInterfaceIdiom -1
_indicators (
    "<UIView: 0x100b0d820; frame = (-3.5 -3.5; 7 7); layer = <CALayer: 0x1c4227c00>>",
    "<UIView: 0x100b0da00; frame = (-3.5 -3.5; 7 7); layer = <CALayer: 0x1c4227cc0>>",
    "<UIView: 0x100b0dbe0; frame = (-3.5 -3.5; 7 7); layer = <CALayer: 0x1c4227d20>>",
    "<UIView: 0x100b0ddc0; frame = (-3.5 -3.5; 7 7); layer = <CALayer: 0x1c4227da0>>"
)
_currentPage 0
_displayedPage 0
_pageControlFlags (null)
_currentPageImage (null)
_pageImage (null)
_currentPageImages (null)
_pageImages (null)
_backgroundVisualEffectView (null)
_currentPageIndicatorTintColor UIExtendedGrayColorSpace 0 1
_pageIndicatorTintColor UIExtendedSRGBColorSpace 0 0 1 1
_legibilitySettings (null)
_numberOfPages 4        

从属性名我们发现了几个比较重要的属性_currentPageImage_pageImage_currentPageImages_pageImages,通过属性名称可以判断这些就是我们要找的属性,接着使用KVC为其设置我们自己的图片,代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[pageControler setValue:[UIImage imageNamed:@"line"] forKeyPath:@"pageImage"];
[pageControler setValue:[UIImage imageNamed:@"current"] forKeyPath:@"currentPageImage"];

实现效果如下:

修改后的效果

在我们需要修改系统提供UI界面而又束手无策时可以使用runtime获取属性来查看是否有可以使用的属性或方法,接着可以使用KVC获取相关值或进行赋值操作,这种方法可能也会存在风险,如果获取的是苹果禁用的私有API那就只能乖乖想别的方法了,不过KVC提供了一种修改系统实现的思路。

KVC底层实现

首先,继续第一个栗子,我们实现如下代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#import <Foundation/Foundation.h>

@interface Person : NSObject
//为了方便查看重写的代码将name改成cjmName
@property (nonatomic, copy) NSString *cjmName;
@property (nonatomic, assign) NSUInteger age;
- (void)showMyself;

@end

@implementation Person

@synthesize cjmName = _cjmName;
@synthesize age = _age;

- (void)showMyself {
    NSLog(@"Name: %@ Age: %ld", self.cjmName, self.age);
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Person *p = [[Person alloc] init];
        
        [p setValue:@"Jiaming Chen" forKey:@"cjmName"];
        [p setValue:@22 forKey:@"age"];
        
        p.cjmName = @"CCCC";
        
        [p showMyself];
    }
    return 0;
}

接着使用clang -rewrite-objc main.m重写为cpp文件,查看main函数重写后的代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main(int argc, const char * argv[]) {
    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;

        Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc")), sel_registerName("init"));

        ((void (*)(id, SEL, id _Nullable, NSString *))(void *)objc_msgSend)((id)p, sel_registerName("setValue:forKey:"), (id _Nullable)(NSString *)&__NSConstantStringImpl__var_folders_1f_dz4kq57d4b19s4tfmds1mysh0000gn_T_main_080287_mi_1, (NSString *)&__NSConstantStringImpl__var_folders_1f_dz4kq57d4b19s4tfmds1mysh0000gn_T_main_080287_mi_2);
        ((void (*)(id, SEL, id _Nullable, NSString *))(void *)objc_msgSend)((id)p, sel_registerName("setValue:forKey:"), (id _Nullable)((NSNumber *(*)(Class, SEL, int))(void *)objc_msgSend)(objc_getClass("NSNumber"), sel_registerName("numberWithInt:"), 22), (NSString *)&__NSConstantStringImpl__var_folders_1f_dz4kq57d4b19s4tfmds1mysh0000gn_T_main_080287_mi_3);

        ((void (*)(id, SEL, NSString *))(void *)objc_msgSend)((id)p, sel_registerName("setCjmName:"), (NSString *)&__NSConstantStringImpl__var_folders_1f_dz4kq57d4b19s4tfmds1mysh0000gn_T_main_080287_mi_4);

        ((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("showMyself"));
    }
    return 0;
}

通过上面的重写代码似乎没有什么特别的发现,对于setValue:forKey:方法的调用与普通方法相同,所以,这里猜测底层实现可能是在执行KVC相关方法时,在继承树上沿着isa指针按照之前讲解的顺序去查找相关属性进行赋值和获取值的操作。如有读者清楚还请不吝赐教。

备注

由于作者水平有限,难免出现纰漏,如有问题还请不吝赐教。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.10.13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
iOS runtime探究(二): 从runtime开始深入理解OC消息转发机制你要知道的runtime都在这里
你要知道的runtime都在这里 转载请注明出处 https://cloud.tencent.com/developer/user/1605429 本文主要讲解runtime相关知识,从原理到实践,由于包含内容过多分为以下五篇文章详细讲解,可自行选择需要了解的方向: 从runtime开始: 理解面向对象的类到面向过程的结构体 从runtime开始: 深入理解OC消息转发机制 从runtime开始: 理解OC的属性property 从runtime开始: 实践Category添加属性与黑魔法method sw
WWWWDotPNG
2018/04/10
9580
iOS runtime探究(二): 从runtime开始深入理解OC消息转发机制你要知道的runtime都在这里
iOS进阶_KVC(&KVC赋值取值过程分析&KVC自定义&异常处理)
在WTPerson.m中我们让accessInstanceVariablesDirectly返回NO,则程序直接崩溃。
编程怪才-凌雨画
2020/09/18
8510
编码篇-精析OC史诗级技术之KVC
不得不承认KVC在开发过程中是神器一般的存在。如果正确灵活使用kvc,会使得整个开发过程轻松很多。简单而强大。
進无尽
2018/09/12
1.3K0
编码篇-精析OC史诗级技术之KVC
【iOS 开发】Objective - C 面向对象 - 方法 | 成员变量 | 隐藏封装 | KVC | KVO | 初始化 | 多态
Object-C 方法传参机制 : OC 中得参数传递都是值传递, 传入参数的是参数的副本; 
韩曙亮
2023/03/27
9550
KVO 正确使用姿势进阶及底层实现你要知道的KVC、KVO、Delegate、Notification都在这里
你要知道的KVC、KVO、Delegate、Notification都在这里 转载请注明出处 https://cloud.tencent.com/developer/user/1605429 本系列文章主要通过讲解KVC、KVO、Delegate、Notification的使用方法,来探讨KVO、Delegate、Notification的区别以及相关使用场景,本系列文章将分一下几篇文章进行讲解,读者可按需查阅。 KVC 使用方法详解及底层实现 KVO 正确使用姿势进阶及底层实现 Protocol与Dele
WWWWDotPNG
2018/04/10
1.6K0
KVO 正确使用姿势进阶及底层实现你要知道的KVC、KVO、Delegate、Notification都在这里
iOS - 关于 KVC 的一些总结
我们可以使用setter方法为currentBalance属性赋值,这是直接的,但缺乏灵活性。
师大小海腾
2020/04/16
1.9K0
程序员面试闪充 -- KVC&KVO
一、键值编码KVC kvc&kvo视频讲解 1、介绍 由于oc的语言特性,使得开发者根本不必进行任何操作就可以进行属性的动态读写,这种方式就是Key Value Coding(简称KVC)。 KVC的操作方法由NSKeyValueCoding协议提供,而NSObject就实现了这个协议,也就是说OC中几乎所有的对象都支持KVC操作,常用的KVC操作方法如下: 动态设置:setValue:属性值 forKey:属性名用于简单路径;setValue:属性值 forKeyPath:属性路径用于复合路径,例如Pe
谦谦君子修罗刀
2018/05/02
7530
iOS底层学习——KVC上篇
键值编码是由NSKeyValueCoding非正式协议启用的一种机制,对象采用该机制来提供对其属性的间接访问。当对象符合键值编码时,其属性可通过字符串参数通过简洁、统一的消息传递接口进行寻址。这种间接访问机制补充了实例变量及其相关访问器方法提供的直接访问。
CC老师
2021/08/25
4400
KVC原理与数据筛选
Tech 导读 通过分析Foundation框架中的KVC部分并结合案例分析KVC原理,解释为什么属性为简单数据类型的时候可以设置其值为字符串类型且不会崩溃的真实原因。最后举例说明KVC使用的场景和高级应用。
京东技术
2023/01/05
8830
KVC原理与数据筛选
RunTime 之常规操作
有关Runtime的知识总结,我本来想集中写成一篇文章的,但是最后发现实在是太长,而且不利于阅读,最后分成了如下几篇:
進无尽
2018/09/12
5940
RunTime 之常规操作
iOS底层学习——KVC下篇
除了对当前对象的属性进行赋值外,还可以对其更深层的对象进行赋值。例如,对当前对象的location属性的country属性进行赋值。KVC进行多级访问时,直接类似于属性调用一样用点语法进行访问即可。
CC老师
2021/08/25
4650
iOS_KVC:Key-Value Coding-1(使用)
以上2个方法如果Key值不对(即该属性不存在),则会触发valueForUndefinedKey:方法,默认会抛出NSUndefinedKeyException异常,导致crash。
mikimo
2022/07/20
3910
iOS_KVC:Key-Value Coding-1(使用)
iOS:KVO/KVC 的概述与使用
KVO 一,概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。 二,使用方法 系统框架已经支持KVO,所以程序员在使用的时候非常简单。 1. 注册,指定被观察者的属性, 2. 实现回调方法 3. 移除观察 三,实例: 假设一个场景,股票的价格显示在当前屏幕上,当股票价格更改的时候,实时显示更新其价格。 1.定义DataModel, [cpp] view
用户1941540
2018/05/11
1.5K0
KVC原理分析
首先呢,我们来聊一聊苹果开发文档。不知道诸位在平时开发中是否有查阅苹果官方文档的习惯,反正我在遇到一些不太清楚的地方的时候首先会去官方文档上看看是否能找到对应的说明,如果没找到,再去百度或者Google。
拉维
2021/03/25
6840
KVC原理分析
iOS底层原理总结 - 探寻Runtime本质(四)
首先来看一道面试题。 下列代码中Person继承自NSObject,Student继承自Person,写出下列代码输出内容。
xx_Cc
2018/08/02
9280
iOS底层原理总结 - 探寻Runtime本质(四)
iOS runtime探究(四): 从runtiem开始实践Category添加属性与黑魔法method swizzling你要知道的runtime都在这里
你要知道的runtime都在这里 转载请注明出处 https://cloud.tencent.com/developer/user/1605429 本文主要讲解runtime相关知识,从原理到实践,由于包含内容过多分为以下五篇文章详细讲解,可自行选择需要了解的方向: 从runtime开始: 理解面向对象的类到面向过程的结构体 从runtime开始: 深入理解OC消息转发机制 从runtime开始: 理解OC的属性property 从runtime开始: 实践Category添加属性与黑魔法method sw
WWWWDotPNG
2018/04/10
8300
iOS runtime探究(四): 从runtiem开始实践Category添加属性与黑魔法method swizzling你要知道的runtime都在这里
iOS开发·KVO用法,原理与底层实现: runtime模拟实现KVO监听机制(Blcok及Delgate方式)
KVO 是 Objective-C 对 观察者模式(Observer Pattern)的实现。当被观察对象的某个属性发生更改时,观察者对象会获得通知。有意思的是,你不需要给被观察的对象添加任何额外代码,就能使用 KVO 。这是怎么做到的?
陈满iOS
2018/09/10
2.1K0
iOS开发·KVO用法,原理与底层实现: runtime模拟实现KVO监听机制(Blcok及Delgate方式)
OC - Block 详解
通过 Clang 将以下 Block 代码转换为 C++ 代码,来分析 Block 的底层实现。
师大小海腾
2020/04/16
3.2K0
OC - Block 详解
iOS 底层原理探索 之 KVC 我愿称之它为魔法...
键值编码是一种由NSKeyValueCoding非正式协议启用的机制,对象采用该机制来提供对其属性的间接访问。当对象符合键值编码时,其属性可通过字符串参数通过简洁、统一的消息传递接口进行寻址。这种间接访问机制补充了实例变量及其相关访问器方法提供的直接访问。
CC老师
2021/08/25
4280
iOS kvc
今天,他们遇到了kvc第二次去学习它,在网上看了很多博客,这似乎不符合我的口味,为了提取一些以下的。总结自己的。
全栈程序员站长
2022/07/06
2140
推荐阅读
相关推荐
iOS runtime探究(二): 从runtime开始深入理解OC消息转发机制你要知道的runtime都在这里
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验