• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

ios - 如何将 KVO 应用于运行时创建的 @dynamic 属性?

[复制链接]
菜鸟教程小白 发表于 2022-12-13 16:00:26 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

我正在尽力解释它是如何工作的,但它非常令人困惑且冗长。如果有什么我可以澄清的,请告诉我。

我被 KVC 和 KVO 的概念困住了。
我有一个入口类 (NSObject)。
入口类具有私有(private)变量 objectProperties (NSDictionary),其值来自服务器。

假设 objectProperties 有键“价格”、“折扣”等,那么我想在 Entry 类的实例中创建动态属性。

这些键可能会根据响应和动态变量而有所不同。

现在,当用户想要在相同的属性上使用 KVO 时,它们将无法访问。

用于创建动态属性,它是 Getter/Setter:

-(NSString*)propNameNSString*)name {
    name = [name stringByReplacingOccurrencesOfString":" withString""];
    NSRange r;
    r.length = name.length -1 ;
    r.location = 1;
    NSString* firstChar = [name stringByReplacingCharactersInRange:r withString""];
    if([firstChar isEqualToString:[firstChar lowercaseString]])
    {return name;}
    r.length = 1;
    r.location = 0;
    NSString* theRest = [name stringByReplacingCharactersInRange:r withString""];
    return [NSString stringWithFormat"%@%@", [firstChar lowercaseString] , theRest];
}

-(NSString*)setterNameNSString*)name {
    name = [self propName:name];
    NSRange r;
    r.length = name.length -1 ;
    r.location = 1;
    NSString* firstChar = [name stringByReplacingCharactersInRange:r withString""];
    r.length = 1;
    r.location = 0;
    NSString* theRest = [name stringByReplacingCharactersInRange:r withString""];
    return [NSString stringWithFormat"set%@%@", [firstChar uppercaseString] , theRest];
}


-(NSString*)propNameFromSetterNameNSString*)name {
    NSRange r;
    r.length = 3 ;
    r.location = 0;
    NSString* propName = [name stringByReplacingCharactersInRange:r withString""];
    return [self propName:propName];  }


-(NSString*)ivarNameNSString*)name  {
    NSRange r;
    r.length = name.length -1 ;
    r.location = 1;
    NSString* firstChar = [name stringByReplacingCharactersInRange:r withString""].lowercaseString;

 if([firstChar isEqualToString:@"_"])
        return name;
    r.length = 1;
    r.location = 0;
    NSString* theRest = [name stringByReplacingCharactersInRange:r withString:@""];
    return [NSString stringWithFormat:@"_%@%@",firstChar, theRest];  }


NSObject *getter(id self, SEL _cmd)
{
    NSString* name = NSStringFromSelector(_cmd);
    NSString* ivarName = [self ivarName:name];
    Ivar ivar = class_getInstanceVariable([self class], [ivarName UTF8String]);
    return object_getIvar(self, ivar);
}

void setter(id self, SEL _cmd, NSObject *newObj)
{
    NSString* name = [self propNameFromSetterName:NSStringFromSelector(_cmd)];
    NSString* ivarName = [self ivarName:name];
    Ivar ivar = class_getInstanceVariable([self class], [ivarName UTF8String]);
    id oldObj = object_getIvar(self, ivar);
    if (![oldObj isEqual: newObj])
    {
        object_setIvar(self, ivar, newObj);
        [newObj copy];
    }
}

-(NSDictionary *)createPropertiesNSArray *)propNames {
    NSMutableDictionary* keys = [[NSMutableDictionary alloc]init];
    for(NSString* key in propNames)
    {
        NSString* propName = [self propName: key];
        NSString* iVarName = [self ivarName:propName];

        class_addIvar([self class], [iVarName UTF8String] , sizeof(NSObject*), log2(sizeof(NSObject*)), @encode(NSObject));

        objc_property_attribute_t a1 = { "T", "@\"NSObject\"" };
        objc_property_attribute_t a2 = { "&", "" };
        objc_property_attribute_t a3 = { "N", "" };
        objc_property_attribute_t a4 = { "V", [iVarName UTF8String] };
        objc_property_attribute_t attrs[] = { a1, a2, a3, a4};

        class_addProperty([self class], [propName UTF8String], attrs, 4);
        class_addMethod([self class], NSSelectorFromString(propName), (IMP)getter, "@@:");
        class_addMethod([self class], NSSelectorFromString([self setterName:propName]), (IMP)setter, "v@:@");

        id val = [self.objectProperties objectForKey:key];
        [keys setValue:val forKey:propName];
    }
    return keys;
}

但是当用户想要观察任何属性时,在用户类中是无法访问的。

我很困惑如何创建动态属性和应用 KVO。

我也尝试过创建 Entry 类的子类,即(用户在其末尾创建的 myEntry)并在那里定义所有变量。但是我如何在那里设置它的值?因为我希望该属性是只读的。



Best Answer-推荐答案


首先:实例化类后不能创建 ivars。这是因为已创建实例的内存占用会发生变化。所以令人惊讶的是 -createProperties: 是一个实例方法。

此外,KVO 的工作原理是在运行时对观察到的实例的类进行子类化并将新类分配给观察到的实例(isa-swizzling)。这显然是一个问题,如果你在注册 KVO 后更改了基类。

然而,所有所说的都适用于自动 KVO。您可以改用手动 KVO。只需将 KVO 通知添加到您的访问者即可。

但正如评论:你应该重新考虑你的整个概念。

关于ios - 如何将 KVO 应用于运行时创建的 @dynamic 属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36833074/

回复

使用道具 举报

懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝2

帖子830918

发布主题
阅读排行 更多
广告位

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap