IKImageBrowserView 延迟加载?
为了使用IKImageBrowserView
,必须使用以下方法实现数据源
– numberOfItemsInImageBrowser:
– imageBrowser:itemAtIndex:
这与具有以下数据源方法的NSTableView
没有什么不同,
– numberOfRowsInTableView:
– tableView:objectValueForTableColumn:row:
但是,令人不安的区别是而 NSTableView
在调用 之前会考虑当前可见的内容 - tableView:objectValueForTableColumn:row:
,IKImageBrowserView
似乎会迭代在 – numberOfItemsInImageBrowser:
中给出的整个范围内,并要求 imageBrowser:itemAtIndex:
。不幸的是,数据源有时由数十万个项目支持,加载所有不必要的项目是一种可怕的浪费。无论如何,有没有办法让 IKImageBrowserView 只加载可见的项目(当然是预加载),就像 NSTableView 那样?
更新
我尝试编写一个 NSProxy
子类,它确实有效。 (好吧,稍后会详细介绍)它看起来像这样
// .h file
#import <Foundation/Foundation.h>
@interface ILArrayItemProxy : NSProxy
- (id)initWithArray:(id)array index:(NSUInteger)index;
+ (id)proxyWithArray:(id)array index:(NSUInteger)index;
@end
// .m file
#import "ILArrayItemProxy.h"
@interface ILArrayItemProxy() {
id _array;
NSUInteger _index;
}
@property (readonly) id target;
@end
@implementation ILArrayItemProxy
- (id)initWithArray:(id)array index:(NSUInteger)index {
_array = array;
_index = index;
return self;
}
- (id)target {
return [_array objectAtIndex:_index];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
+ (id)proxyWithArray:(id)array index:(NSUInteger)index {
return [[ILArrayItemProxy alloc] initWithArray:array index:index];
}
@end
现在,当 imageBrowser 请求 – imageBrowser:itemAtIndex:
时,我会返回
[ILArrayItemProxy proxyWithArray:self.arrangedObjects index:index];
这非常有效!确实实现了延迟加载,并且我不再立即从存储中检索所有对象。然而,在任何视图上调用 reloadData
时,问题就会随之而来。
这是来自 NSTableView
IKImageBrowserView
的错误消息,
Cannot update for observer <NSAutounbinderObservance 0x105889dd0> for the key path
"objectValue.status" from <NSTableCellView 0x105886a80>, most likely because the value
for the key "objectValue" has changed without an appropriate KVO notification being sent.
Check the KVO-compliance of the NSTableCellView class.
2012-01-29 11:48:01.304 [62895:707] (
0 CoreFoundation 0x00007fff92bf6286 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff91d3ad5e objc_exception_throw + 43
2 CoreFoundation 0x00007fff92bf60ba +[NSException raise:format:arguments:] + 106
3 CoreFoundation 0x00007fff92bf6044 +[NSException raise:format:] + 116
4 Foundation 0x00007fff9154b519 -[NSKeyValueNestedProperty object:withObservance:didChangeValueForKeyOrKeys:recurse:forwardingValues:] + 689
5 Foundation 0x00007fff9154986f NSKeyValueDidChange + 186
6 Foundation 0x00007fff914f60fb -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] + 130
7 AppKit 0x00007fff90a2c26d -[NSTableRowData _addViewToRowView:atColumn:row:] + 434
8 AppKit 0x00007fff90a2bf81 -[NSTableRowData _addViewsToRowView:atRow:] + 200
9 AppKit 0x00007fff90a2abe3 -[NSTableRowData _addRowViewForVisibleRow:withPriorView:] + 404
10 AppKit 0x00007fff90a2a9e2 -[NSTableRowData _addRowViewForVisibleRow:withPriorRowIndex:inDictionary:withRowAnimation:] + 184
11 AppKit 0x00007fff90a2a928 -[NSTableRowData _addRowViewForVisibleRow:] + 38
12 AppKit 0x00007fff90a2a06c -[NSTableRowData _unsafeUpdateVisibleRowEntries] + 448
13 AppKit 0x00007fff90a29e87 -[NSTableRowData updateVisibleRowViews] + 95
14 AppKit 0x00007fff909c1c56 -[NSTableView viewWillDraw] + 156
15 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
16 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
17 AppKit 0x00007fff909254a2 -[NSScrollView viewWillDraw] + 43
18 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
19 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
20 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
21 AppKit 0x00007fff90924f7b -[NSSplitView viewWillDraw] + 67
22 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
23 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
24 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
25 AppKit 0x00007fff90924f7b -[NSSplitView viewWillDraw] + 67
26 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
27 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
28 AppKit 0x00007fff90923952 -[NSView _sendViewWillDrawInRect:clipRootView:suppressRecursion:] + 1358
29 AppKit 0x00007fff909226c1 -[NSView displayIfNeeded] + 1039
30 AppKit 0x00007fff9091e6fa -[NSAnimationManager animationTimerFired:] + 2593
31 Foundation 0x00007fff91537014 __NSFireTimer + 102
32 CoreFoundation 0x00007fff92baaf84 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
33 CoreFoundation 0x00007fff92baaad6 __CFRunLoopDoTimer + 534
34 CoreFoundation 0x00007fff92b8b471 __CFRunLoopRun + 1617
35 CoreFoundation 0x00007fff92b8aae6 CFRunLoopRunSpecific + 230
36 HIToolbox 0x00007fff8cdf63d3 RunCurrentEventLoopInMode + 277
37 HIToolbox 0x00007fff8cdfd58f ReceiveNextEventCommon + 181
38 HIToolbox 0x00007fff8cdfd4ca BlockUntilNextEventMatchingListInMode + 62
39 AppKit 0x00007fff908e63f1 _DPSNextEvent + 659
40 AppKit 0x00007fff908e5cf5 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 135
41 AppKit 0x00007fff908e262d -[NSApplication run] + 470
42 AppKit 0x00007fff90b6180c NSApplicationMain + 867
另一方面,如果我要调用它的 reloadData
,它就会挂在我身上,而不会出现任何类型的错误消息>。
是的,我成功地用一个问题替换了另一个问题,这就是生活吗?
In order to work with the IKImageBrowserView
, one must implement a datasource with the following methods
– numberOfItemsInImageBrowser:
– imageBrowser:itemAtIndex:
This is not dissimilar to NSTableView
, which has the following datasource methods
– numberOfRowsInTableView:
– tableView:objectValueForTableColumn:row:
However, the disturbing difference is that whereas NSTableView
takes into account what's currently visible before calling – tableView:objectValueForTableColumn:row:
, IKImageBrowserView
seems to iterate over the entire range given in – numberOfItemsInImageBrowser:
and ask for imageBrowser:itemAtIndex:
. Unfortunately, the datasource is sometimes backed by hundreds of thousands of items, loading all the unnecessary ones is a terrible waste. Is there anyway to make IKImageBrowserView
only load the items visible, (+preloading of course) just like the NSTableView
does?
Update
I tried writing a NSProxy
subclass and it indeed worked. (well, more on that in a sec) It looks like this
// .h file
#import <Foundation/Foundation.h>
@interface ILArrayItemProxy : NSProxy
- (id)initWithArray:(id)array index:(NSUInteger)index;
+ (id)proxyWithArray:(id)array index:(NSUInteger)index;
@end
// .m file
#import "ILArrayItemProxy.h"
@interface ILArrayItemProxy() {
id _array;
NSUInteger _index;
}
@property (readonly) id target;
@end
@implementation ILArrayItemProxy
- (id)initWithArray:(id)array index:(NSUInteger)index {
_array = array;
_index = index;
return self;
}
- (id)target {
return [_array objectAtIndex:_index];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation invokeWithTarget:self.target];
}
+ (id)proxyWithArray:(id)array index:(NSUInteger)index {
return [[ILArrayItemProxy alloc] initWithArray:array index:index];
}
@end
Now, when the imageBrowser asks for – imageBrowser:itemAtIndex:
, I would return
[ILArrayItemProxy proxyWithArray:self.arrangedObjects index:index];
This works very well! Lazy loading is indeed achieved and I am no longer retrieving all the objects from the store at once. However, upon calling reloadData
on any of the views, troubles ensue.
Here is the error message from NSTableView
Cannot update for observer <NSAutounbinderObservance 0x105889dd0> for the key path
"objectValue.status" from <NSTableCellView 0x105886a80>, most likely because the value
for the key "objectValue" has changed without an appropriate KVO notification being sent.
Check the KVO-compliance of the NSTableCellView class.
2012-01-29 11:48:01.304 [62895:707] (
0 CoreFoundation 0x00007fff92bf6286 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff91d3ad5e objc_exception_throw + 43
2 CoreFoundation 0x00007fff92bf60ba +[NSException raise:format:arguments:] + 106
3 CoreFoundation 0x00007fff92bf6044 +[NSException raise:format:] + 116
4 Foundation 0x00007fff9154b519 -[NSKeyValueNestedProperty object:withObservance:didChangeValueForKeyOrKeys:recurse:forwardingValues:] + 689
5 Foundation 0x00007fff9154986f NSKeyValueDidChange + 186
6 Foundation 0x00007fff914f60fb -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] + 130
7 AppKit 0x00007fff90a2c26d -[NSTableRowData _addViewToRowView:atColumn:row:] + 434
8 AppKit 0x00007fff90a2bf81 -[NSTableRowData _addViewsToRowView:atRow:] + 200
9 AppKit 0x00007fff90a2abe3 -[NSTableRowData _addRowViewForVisibleRow:withPriorView:] + 404
10 AppKit 0x00007fff90a2a9e2 -[NSTableRowData _addRowViewForVisibleRow:withPriorRowIndex:inDictionary:withRowAnimation:] + 184
11 AppKit 0x00007fff90a2a928 -[NSTableRowData _addRowViewForVisibleRow:] + 38
12 AppKit 0x00007fff90a2a06c -[NSTableRowData _unsafeUpdateVisibleRowEntries] + 448
13 AppKit 0x00007fff90a29e87 -[NSTableRowData updateVisibleRowViews] + 95
14 AppKit 0x00007fff909c1c56 -[NSTableView viewWillDraw] + 156
15 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
16 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
17 AppKit 0x00007fff909254a2 -[NSScrollView viewWillDraw] + 43
18 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
19 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
20 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
21 AppKit 0x00007fff90924f7b -[NSSplitView viewWillDraw] + 67
22 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
23 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
24 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
25 AppKit 0x00007fff90924f7b -[NSSplitView viewWillDraw] + 67
26 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
27 AppKit 0x00007fff90924c11 -[NSView viewWillDraw] + 666
28 AppKit 0x00007fff90923952 -[NSView _sendViewWillDrawInRect:clipRootView:suppressRecursion:] + 1358
29 AppKit 0x00007fff909226c1 -[NSView displayIfNeeded] + 1039
30 AppKit 0x00007fff9091e6fa -[NSAnimationManager animationTimerFired:] + 2593
31 Foundation 0x00007fff91537014 __NSFireTimer + 102
32 CoreFoundation 0x00007fff92baaf84 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
33 CoreFoundation 0x00007fff92baaad6 __CFRunLoopDoTimer + 534
34 CoreFoundation 0x00007fff92b8b471 __CFRunLoopRun + 1617
35 CoreFoundation 0x00007fff92b8aae6 CFRunLoopRunSpecific + 230
36 HIToolbox 0x00007fff8cdf63d3 RunCurrentEventLoopInMode + 277
37 HIToolbox 0x00007fff8cdfd58f ReceiveNextEventCommon + 181
38 HIToolbox 0x00007fff8cdfd4ca BlockUntilNextEventMatchingListInMode + 62
39 AppKit 0x00007fff908e63f1 _DPSNextEvent + 659
40 AppKit 0x00007fff908e5cf5 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 135
41 AppKit 0x00007fff908e262d -[NSApplication run] + 470
42 AppKit 0x00007fff90b6180c NSApplicationMain + 867
IKImageBrowserView
on the other hand would just hang on me without any kind of error message if I were to call its reloadData
.
So yea, I managed to replace one problem with another, c'est la vie?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论