这是一个非常广泛/模糊的问题,但这里有.提前道歉.
我正在构建的应用程序(桌面应用程序)采用不同类型的输入来生成QR代码(我只是构建它来学习一些Obj-C / Cocoa).用户可以在允许输入纯文本(单文本字段),VCard / MeCard数据(多个文本字段)和其他内容的不同视图之间切换.无论输入如何,结果都是QR码.
为了保持包含,我想将视图用作视图控制器,因此它们处理它们自己的输入,并且可以简单地将包含所有数据的通用“数据编码”对象“发送”到中央编码器.即纯文本视图将使用其文本字段的文本创建数据对象,而VCard / MeCard视图将使用其所有字段来生成结构化的VCard / MeCard数据.
我可以在代码中手动绑定所有这些东西,但我真的想学习bindings / KVO如何帮助我.唉,在阅读了Apple的开发人员文档,以及我能找到的更简单的教程/示例之后,我仍然不确定如何将它应用到我的应用程序中.
例如:用户在VCard视图中编辑文本字段.每次更新都会通知VCard视图控制器并“重新计算”数据对象.然后,中央编码器控制器被通知更新的数据对象,并对数据进行编码.
所有这一点,是输入视图可以完全独立创建,并且可以包含各种输入字段.然后,他们处理自己的输入,并“返回”编码器可以使用的通用数据对象.在内部,视图观察它们的输入以更新数据对象,并且外部编码器仅需要观察数据对象.
麻烦的是我不知道如何使这一切发生并保持解耦.输入视图和其字段之间是否应该有对象控制器?视图和编码器之间应该有另一个吗?我需要什么?如果有人有一个很好的教程链接,请分享.
同样,我可以推出自己的通知系统和粘合代码,但我认为重点是避免这种情况.
最佳答案 绝对是一个模糊的问题,但一个初学者到另一个,我觉得你的痛苦:)
我下载并解压缩每个示例并经常浏览它们.我发现让我超越驼峰是最有价值的事情.我绝对建议不要放弃这些例子.我砍掉了this script来下载并打开它们.
就良好的KVO模式而言,我发现技术described here非常有用.然而,在Objective-C 2.0中它是doesn’t work as-is.此外,他没有详细说明它是如何实际使用的.这就是我的工作:
KVODispatcher.h是这样的:
#import <Foundation/Foundation.h>
@interface KVODispatcher : NSObject {
id owner;
}
@property (nonatomic, retain) id owner;
- (id) initWithOwner:(id)owner;
- (void)startObserving:(id)object keyPath:(NSString*)keyPath
options:(NSKeyValueObservingOptions)options
selector:(SEL)sel;
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context;
@end
KVODispatcher.m如下:
#import "KVODispatcher.h"
#import <objc/runtime.h>
@implementation KVODispatcher
@synthesize owner;
- (id)initWithOwner:(id)theOwner
{
self = [super init];
if (self != nil) {
self.owner = theOwner;
}
return self;
}
- (void)startObserving:(id)object
keyPath:(NSString*)keyPath
options:(NSKeyValueObservingOptions)options
selector:(SEL)sel
{
// here is the actual KVO registration
[object addObserver:self forKeyPath:keyPath options:options context:sel];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
// The event is delegated back to the owner
// It is assumed the method identified by the selector takes
// three parameters 'keyPath:object:change:'
objc_msgSend(owner, (SEL)context, keyPath, object, change);
// As noted, a variation of this technique could be
// to expand the data passed in to 'initWithOwner' and
// have that data passed to the selected method here.
}
@end
然后你可以注册观察这样的事件:
KVODispatcher* dispatcher = [[KVODispatcher alloc] initWithOwner:self];
[dispatcher startObserving:theObject
keyPath:@"thePath"
options:NSKeyValueChangeNewKey
selector:@selector(doSomething:object:change:)];
在执行上述操作的同一个对象中,您可以使用如下方法:
- (void) doSomething:(NSString *)keyPath
object:(id)object
change:(NSDictionary *)change {
// do your thing
}
您可以根据需要使用这些“doSomething”类型的方法.只要他们使用相同的参数(keyPath:object:change :)就可以了.每个对象有一个调度程序,希望接收有关任意数量对象更改的任意数量的通知.
我喜欢它:
>每个类只能有一个observeValueForKeyPath,但您可能想要观察几件事.自然的下一个想法是“嘿,也许我可以通过一个选择器”
>哦,但是除非使用像NSNotification这样的包装器对象,否则不能通过performSelector传递多个参数.谁想要清理包装器对象.
>当超类也使用KVO时,覆盖observeValueForKeyPath会使任何通用方法变得困难 – 您必须知道哪些通知要传递给超类以及要保留哪些通知.
>谁想要在每个对象中重新实现相同的基于泛型选择器的observeValueForKeyPath?最好只做一次并重复使用它.
一个不错的变化可能是将另一个字段(如id additionalContext)添加到KVODispatcher,并在objc_msgSend调用中传递该additionalContext对象.使用它来隐藏在观察到的数据发生变化时需要更新的UI对象会很有用.甚至可能是NSArray.