objective-c – 在使用组合扩展NSMutableDictionary时支持KVO

objective-c – 在使用组合扩展NSMutableDictionary时支持KVO,第1张

概述我有一个NSMutableDictionary对象数组,它们显示在主 – 详细信息界面中,其中包含一些文本字段和一堆复选框.控件绑定到字典键,通过数组控制器的选择访问. 我想添加一些逻辑,当清除另一个复选框时清除一个复选框,并恢复原始值,如果它在同一个会话中重新检查.由于我需要将存储与字典相关联,并且还需要添加代码,我以为我会使用composition来扩展NSMutableDictionary. 我有一个NSMutableDictionary对象数组,它们显示在主 – 详细信息界面中,其中包含一些文本字段和一堆复选框.控件绑定到字典键,通过数组控制器的选择访问.

我想添加一些逻辑,当清除另一个复选框时清除一个复选框,并恢复原始值,如果它在同一个会话中重新检查.由于我需要将存储与字典相关联,并且还需要添加代码,我以为我会使用composition来扩展NSMutableDictionary.

这就是我所做的:

>我创建了一个包含NSMutableDictionary的libraryEntry子类.
>我实现了forwardInvocation:,respondsToSelector:,methodSignatureForSelector:,以及一些试错了valueForUndefinedKey:.
>我创建了我的转发器对象.
>我按原样离开了绑定.

它加载数据很好,但我猜测KVO将无法正常工作.我猜测绑定器在我的对象上调用addobserver:但我没有实现任何特殊的处理它.

我想简单地重写addobserver:并将消息转发到字典.但是如果我这样做,observeValueForKey:notification将不会来自我的对象(addobserver的原始接收者),而是来自字典.

在我尝试为这些KVO调用实现更透明的转发之前,我想……这变得越来越混乱.我继续阅读“使用组合,而不是子类”来获得这样的行为.对于这种情况,这只是错误的模式吗?为什么?因为KVO?

如果我放弃作曲并选择其中一种替代方案,我似乎会得到更清晰的结果:

>使用装饰器,一个实例观察每个字典
>将临时密钥存储在字典中,让控制器在保存之前将其删除
>取消字典并声明属性

这是我的代码,万一它有用(值是字典):

- (voID)forwardInvocation:(NSInvocation *)anInvocation {    if ([values respondsToSelector:[anInvocation selector]])        [anInvocation invokeWithTarget:values];    else        [super forwardInvocation:anInvocation];}- (BOol)respondsToSelector:(SEL)aSelector {    if ( [super respondsToSelector:aSelector] )        return YES;    else        return [values respondsToSelector:aSelector];}- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {    NSMethodSignature* signature = [super methodSignatureForSelector:selector];    if (!signature) signature = [values methodSignatureForSelector:selector];    return signature;}-(ID)valueForUndefinedKey:(Nsstring *)key {    return [values valueForKey:key];}
解决方法 我认为结合使用Objective-C相关存储和一些块,您可以将任意行为连接到字典(或任何其他符合KVO的对象)并以这种方式解决您的问题.我提出了以下想法,它实现了一个通用的KVO-triggers-block机制,编码和示例似乎做了你想要它做的事情,并且不涉及子类化或装饰基础集合.

首先是这个机制的公共接口:

typedef voID (^KBBehavior)(ID object,Nsstring* keyPath,ID oldValue,ID newValue,ID userInfo);@interface NSObject (KBKVOBehaviorObserver)- (voID)addBehavior: (KBBehavior)block forKeyPath: (Nsstring*)keyPath options: (NSkeyvalueObservingOptions)options userInfo: (ID)userInfo;- (voID)removeBehaviorForKeyPath: (Nsstring*)keyPath;@end

这将允许您将基于块的观察/行为附加到任意对象.您使用复选框描述的任务可能如下所示:

- (voID)testBehaviors{    NSMutableDictionary* myModelDictionary = [NSMutableDictionary dictionary];    KBBehavior behaviorBlock = ^(ID object,ID userInfo)     {        NSMutableDictionary* modelDictionary = (NSMutableDictionary*)object;        NSMutableDictionary* prevIoUsValues = (NSMutableDictionary*)userInfo;        if (nil == newValue || (![newValue boolValue]))        {            // If the master is turning off,turn off the slave,but make a note of the prevIoUs value            ID prevIoUsValue = [modelDictionary objectForKey: @"slaveCheckBox"];            if (prevIoUsValue)                [prevIoUsValues setobject: prevIoUsValue forKey: @"slaveCheckBox"];            else                [prevIoUsValues removeObjectForKey: @"slaveCheckBox"];            [modelDictionary setobject: newValue forKey: @"slaveCheckBox"];        }        else        {            // if the master is turning ON,restore the prevIoUs value of the slave            ID prevValue = [prevIoUsValues objectForKey: @"slaveCheckBox"];            if (prevValue)                [modelDictionary setobject:prevValue forKey: @"slaveCheckBox"];            else                [modelDictionary removeObjectForKey: @"slaveCheckBox"];        }    };    // Set the state...    [myModelDictionary setobject: [NSNumber numberWithBool: YES] forKey: @"slaveCheckBox"];    [myModelDictionary setobject: [NSNumber numberWithBool: YES] forKey: @"masterCheckBox"];    // Add behavior    [myModelDictionary addBehavior: behaviorBlock forKeyPath: @"masterCheckBox" options: NSkeyvalueObservingOptionNew userInfo: [NSMutableDictionary dictionary]];    // turn off the master    [myModelDictionary setobject: [NSNumber numberWithBool: NO] forKey: @"masterCheckBox"];    // we Now expect the slave to be off...    NSLog(@"slaveCheckBox value: %@",[myModelDictionary objectForKey: @"slaveCheckBox"]);    // turn the master back on...    [myModelDictionary setobject: [NSNumber numberWithBool: YES] forKey: @"masterCheckBox"];    // Now we expect the slave to be back on,since that was it's prevIoUs value    NSLog(@"slaveCheckBox value: %@",[myModelDictionary objectForKey: @"slaveCheckBox"]);}

我通过创建一个跟踪块和userInfos的对象来实现块/ KVO连接,然后让它成为KVO观察者.这是我做的:

#import <objc/runtime.h>static voID* kKVOBehaviorsKey = &kKVOBehaviorsKey;    @interface KBKVOBehaviorObserver : NSObject{    NSMutableDictionary* mBehaviorsByKey;    NSMutableDictionary* mUserInfosByKey;}@end@implementation KBKVOBehaviorObserver- (ID)init{    if (self = [super init])    {        mBehaviorsByKey = [[NSMutableDictionary alloc] init];        mUserInfosByKey = [[NSMutableDictionary alloc] init];    }    return self;}- (voID)dealloc{    [mBehaviorsByKey release];    mBehaviorsByKey = nil;    [mUserInfosByKey release];    mUserInfosByKey = nil;    [super dealloc];}- (voID)addBehavior: (KBBehavior)block forKeyPath: (Nsstring*)keyPath userInfo: (ID)userInfo{    @synchronized(self)    {        ID copIEdBlock = [[block copy] autorelease];        [mBehaviorsByKey setobject: copIEdBlock forKey: keyPath];        [mUserInfosByKey setobject: userInfo forKey: keyPath];    }}- (voID)removeBehaviorForKeyPath: (Nsstring*)keyPath{    @synchronized(self)    {        [mUserInfosByKey removeObjectForKey: keyPath];        [mBehaviorsByKey removeObjectForKey: keyPath];    }}- (voID)observeValueForKeyPath:(Nsstring *)keyPath ofObject:(ID)object change:(NSDictionary *)change context:(voID *)context{    if (context == kKVOBehaviorsKey)    {        KBBehavior behavior = nil;        ID userInfo = nil;        @synchronized(self)        {            behavior = [[[mBehaviorsByKey objectForKey: keyPath] retain] autorelease];            userInfo = [[[mUserInfosByKey objectForKey: keyPath] retain] autorelease];        }        if (behavior)         {            ID oldValue = [change objectForKey: NSkeyvalueChangeoldKey];            ID newValue = [change objectForKey: NSkeyvalueChangeNewKey];            behavior(object,keyPath,oldValue,newValue,userInfo);        }    }}@end@implementation NSObject (KBKVOBehaviorObserver)- (voID)addBehavior: (KBBehavior)block forKeyPath: (Nsstring*)keyPath options: (NSkeyvalueObservingOptions)options userInfo: (ID)userInfo{    KBKVOBehaviorObserver* obs = nil;    @synchronized(self)    {        obs = objc_getAssociatedobject(self,kKVOBehaviorsKey);        if (nil == obs)        {            obs = [[[KBKVOBehaviorObserver alloc] init] autorelease];                objc_setAssociatedobject(self,kKVOBehaviorsKey,obs,OBJC_ASSOCIATION_RETAIN);        }    }    // Put the behavior and userInfos into stuff...    [obs addBehavior: block forKeyPath: keyPath userInfo: userInfo];    // add the observation        [self addobserver: obs forKeyPath: keyPath options: options context: kKVOBehaviorsKey];}- (voID)removeBehaviorForKeyPath: (Nsstring*)keyPath{    KBKVOBehaviorObserver* obs = nil;    obs = [[objc_getAssociatedobject(self,kKVOBehaviorsKey) retain] autorelease];        // Remove the observation    [self removeObserver: obs forKeyPath: keyPath context: kKVOBehaviorsKey];    // remove the behavior    [obs removeBehaviorForKeyPath: keyPath];}@end

有点不幸的是,你必须删除观察/行为才能打破原始字典和观察对象之间的传递保留周期,所以如果你不删除行为,你就会泄漏采集.但总的来说这种模式应该是有用的.

希望这可以帮助.

总结

以上是内存溢出为你收集整理的objective-c – 在使用组合扩展NSMutableDictionary时支持KVO全部内容,希望文章能够帮你解决objective-c – 在使用组合扩展NSMutableDictionary时支持KVO所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1071715.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存