IKImageBrowserView 延迟加载?

发布于 2024-12-29 05:24:57 字数 7003 浏览 1 评论 0原文

为了使用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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文