我正在尝试使用KVO来收听NSArray属性上的集合更改事件.在公共场合,该属性是一个只读的NSArray,但是由NSMutableArray ivar支持,以便我可以修改该集合.

我知道我可以将属性设置为新值以获得“设置”更改,但我有兴趣添加,删除,替换更改.如何正确通知NSArray的这些类型的更改?

@interface Model : NSObject

@property (nonatomic,readonly) NSArray *items;

@end

@implementation Model {
    NSMutableArray *_items;
}

- (NSArray *)items {
    return [_items copy];
}

- (void)addItem:(Item *)item {
  [_items addobject:item];
}

@end
Model *model = [[Model alloc] init];

[observer addobserver:model 
      forKeyPath:@"items" 
         options:(NSkeyvalueObservingOptionNew | NSkeyvalueObservingOptionOld) 
         context:NULL];

Item *item = [[Item alloc] init];
[model addItem:newItem];

观察者类:

-(void)observeValueForKeyPath:(Nsstring *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"items"]) {
        //Not called
    }
}

解决方法

首先,您应该了解KVO用于观察对象的属性变化.也就是说,您不能“观察数组”,您会观察索引的集合属性.该属性可以由数组支持或以其他方式实现.只要它符合KVC并以符合KVO标准的方式进行修改,这就足够了. (因此,如果属性是NSArray *类型或使用NSMutableArray *或其他任何东西实现,则无关紧要.)

因此,您正在观察Model的实例,以便更改其items属性.如果您希望观察者获得更改通知,您必须确保始终以符合KVO的方式修改items属性.

在我看来,最好的方法是实现mutable indexed collection accessors并始终使用它们来修改属性.所以,你要实现至少其中一个:

- (void) insertObject:(id)anObject inItemsAtIndex:(NSUInteger)index;
- (void) insertItems:(NSArray *)objects atIndexes:(NSIndexSet *)indexes;

其中一个:

- (void) removeObjectFromItemsAtIndex:(NSUInteger)index;
- (void) removeItemsAtIndexes:(NSIndexSet *)indexes;

当属性由NSMutableArray支持时,上述方法是围绕_items上相应方法的简单包装器.

您编写的用于修改属性的任何其他方法都应该通过其中一种方法.所以,你的-addItem:方法将是:

- (void)addItem:(Item *)item {
    [self insertObject:item inItemsAtIndex:[_items count]];
}

您还可以删除items属性的普通getter,而只显示索引的集合getter:

- (NSUInteger) countOfItems;
- (id) objectinitemsAtIndex:(NSUInteger)index;

但是,如果有一个典型的吸气剂,这是没有必要的.

(这些访问器的存在允许你实现一个非NSArray类型的to-many属性.从KVC的角度来看,对于任何实际的数组类型接口都没有必要.)

就个人而言,我不建议这样做,但是一旦你有了这样的访问器,你也可以通过使用-mutableArrayValueForKey获取属性的类似NSMutableArray的代理来改变属性,然后向它发送变异操作.因此,在这种情况下,您可以[[self mutableArrayValueForKey:@“items”] addobject:item].我不喜欢这个,因为我觉得键值编码是指密钥是数据的时候.它是动态的或存储在像NIB这样的数据文件中,在编译时不知道.当您可以选择使用语言符号(例如选择器)来处理属性时,硬编码键名称就是代码气味.

但是,对于在索引访问器方面实现真正曲折的操作(例如排序),这是合理的.

最后,您可以使用NSKeyValueObserving协议的-willChange …和-didChange …方法在直接修改属性的后备存储时发出更改通知,而无需通过KVO可识别和挂接的突变方法.对于索引的集合属性,可以是-willChange:valuesAtIndexes:forKey:和-didChange:valuesAtIndexes:forKey:methods.就我而言,这是一种更糟糕的代码味道.

ios – 修改由NSMutableArray支持的NSArray的KVO通知的更多相关文章

  1. nsmutablearray – Sprite Kit iOS7 – SKNode UserData属性不存储值

    谢谢解决方法userData属性最初为零.您必须先创建一个字典并进行分配:

  2. ios – UITableView reloadData什么都不做(UITableView不是nil)

    如果您需要查看更多我的代码,请告诉我.我也看了一下beginUpdates和endUpdates的方法,但在我看来,他们一度关注一些变化和用户交互性.我想根据用户选择重新加载整个表.或者还有另一种更好的方法吗?如果没有,请仔细检查并验证myTableView委托是否设置正确.如果您已正确地将表连接到笔尖并且您有一个插座,您也可以在代码中设置它,即在viewDidLoad方法中,通过设置:

  3. 模糊地使用’下标’ – ios 9 Swift 2.0

    我在xcode7.0上使用Swift2.0编写iosapp.在更新到最新版本的xCode7.1之前,完全相同的代码完全正常更新后,我收到此错误:Ambiguoususeof‘subscript’在这些方面:这是全班:Theoriginallibrary解决方法编译器不知道self.itemAttributes[indexPath.section]返回的内容,因为它定义为NSMutableArray

  4. ios – coredata – 将一个属性提取到数组中

    目的:我想从数据库中获取一个属性(从实体)到数组的值.例实体名称=员工Attribute=employeeID我只想把所有的employeeID都填入一个数组/集合.题以下是我的实现,我只是觉得这是一个圆滑的方式,我想知道是否有更好的方法来做到这一点.码解决方法你可以避免最后一个for循环,代替,尝试这个,

  5. ios – 合并之后的KVO通知.ChangesFromContextDidSaveNotification

    在苹果文档中看不到任何东西…那么,对于大多数合理的用例来说,在属性设置级别上,几乎是最低的开销点.当然,对于任何反复提取的更新设计,如我们的运动队应用程序在这里.

  6. ios – 检测UILabel文本中的变化

    当UILabel的文本属性更改时,是否可以设置通知?当我找不到UILabel的UITextFields时,我尝试了一个UITextField,但是它没有起作用.解决方法您可以使用键值观察:

  7. xcode – KVO在Swift工作一次

    编辑:似乎我找到了一个临时解决方案:解决方法KVO需要动态调度,因此需要将动态修改器添加到属性中:动态变量寿命=0

  8. ios – 什么用作KVO的关键路径?

    我有一个视图控制器,其视图发生了变化(例如),我想观察self.view设置为的任何视图的框架.之间有什么区别:和对于第二个,如果视图更改将在新视图的帧更改时仍然收到消息,或者它是否仅在添加观察者时设置的视图帧发送消息?解决方法使用第二个路径.即使“视图”本身发生变化,@“view.frame”也会通知您帧的变化.Cocoa将自动为keyPath“chain”中的每个对象添加观察者.

  9. ios – TabBarController返回null

    我在故事板中有一个tabbarcontroller作为初始视图控制器这是如何返回null的本来就是我想要做的为什么我会变空?

  10. ios – GCD和KVO问题

    我的应用程序想要获取iphone的专辑列表和某些专辑中的所有照片.在应用程序中,我列举了iphone的一张专辑中的照片.由于某些专辑可能有很多照片,考虑到性能,我使用GCD:dispatch_async.但是当KVO调用的tableview单元格更新时,它总是崩溃.我不知道我是否以错误的方式使用KVO或GCD.现在,我使用performSelectorInBackground:替换dispatch

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部