Для работы с 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
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
, с другой стороны, просто висел бы на мне без какого-либо сообщения об ошибке, если бы я назвал его reloadData
.
Так, да, мне удалось заменить одну проблему другой, c'est la vie?