簡體   English   中英

NSOperationQueue 取消特定操作

[英]NSOperationQueue cancel specific operations

問題是我管理的 scrollView 中有很多圖塊。 每個可見圖塊顯示從 URL 加載的圖像或(在第一次 URL 加載后)后台緩存文件。 隱形瓷磚回收(設置新框架並重繪)。

圖像加載取決於平鋪位置。

對於長距離滾動,每個圖塊都會調用多次重繪:每個圖塊在顯示正確的圖像之前多次加載(並顯示)不同的圖像。

所以問題是在添加新之前取消所有先前添加的 tile 操作。

我子類化 NSInvocationOperation 只是為了包含上下文對象來檢測附加到的操作,在添加新操作之前我取消了同一個圖塊的所有操作:

 -(void)loadWithColler:(TileView *)coller {    
    if (queue == nil) {
        queue = [NSOperationQueue new];
    }

    NSInvocationOperationWithContext *loadImageOp = [NSInvocationOperationWithContext alloc];
    [loadImageOp initWithTarget:self selector:@selector(loadImage:) object:loadImageOp];
    [loadImageOp setContext:coller];

    [queue setSuspended:YES];
    NSArray *opers = [queue operations];
    for (NSInvocationOperationWithContext *nextOperation in opers) {

        if ([nextOperation context] == coller) {
            [nextOperation cancel];
        }

    }

    [queue addOperation:loadImageOp]; 
    [queue setSuspended:NO];    
    [loadImageOp release];
}

在操作本身中,我檢查 isCancelled:

    -(void)loadImage:(NSInvocationOperationWithContext *)operation {

        if (operation.isCancelled) return;

        TileView *coller = [operation context];

        /* TRY TO GET FILE FROM CACHE */    
        if (operation.isCancelled) return;

        if (data) {

            /* INIT WITH DATA IF LOADED */

        } else {
            /* LOAD FILE FROM URL AND CACHE IT */
        }

        if (operation.isCancelled) return;

        NSInvocationOperation *setImageOp = [[NSInvocationOperation alloc] initWithTarget:coller selector:@selector(setImage:) object:cachedImage];
        [[NSOperationQueue mainQueue] addOperation:setImageOp];
        [setImageOp release];

    }

但它什么都不做。 有時提前返回有效,但圖塊仍會在正確的圖像之前加載許多圖像。

那我怎么能成功呢? 滾動時這么多不需要的操作會導致主線程延遲嗎? (因為存在延遲,我不知道為什么......所有在后台加載......)

更新:

使用 NSLog: isCancelled 執行時: > 取消 loadImage 方法: >

所以取消工作。

現在我保存對 TileView 對象中最后一個操作的引用,並且僅當調用的操作等於 TileView 操作時才執行 setImage 操作。

沒什么區別...

看起來有很多操作可以將不同的圖像加載到一個接一個調用的圖塊。

還有其他建議嗎?

清關:

有單例 DataLoader(來自它的所有代碼)。 並且所有圖塊都在 drowRect 中調用它:

[[DataLoader sharedDataLoader] loadWithColler:self];

更新:

NSInvocationOperation 子類:

@interface NSInvocationOperationWithContext : NSInvocationOperation {
    id context;
}

@property (nonatomic,retain,readwrite) id context;

@end


@implementation NSInvocationOperationWithContext

@synthesize context;


- (void)dealloc
{
    [context release];
    [super dealloc];
}
@end

非常感謝您幫助!

解決方案:

從下面的答案:需要從 NSOperation 子類化

當我繼承 NSOperation 並將所有 loadImage: 代碼放入它的“main”方法中時(只需將所有代碼移到此處而沒有其他任何內容),並且所有工作都非常完美!

至於滾動延遲:它發生導致將圖像加載到 UIImageView (由於解壓縮和光柵化(據我所知)需要很長時間)。

所以更好的方法是使用 CATiledLayer。 它在后台加載數據並且加載速度更快。

NSOperationQueue 與“setSuspended”相關的工作方式是它不會開始運行在那之后添加到它的新添加的 NSOperations,並且不會開始運行任何當前在其中但尚未開始運行的NSOperations . 您確定您要取消的操作尚未開始嗎?

另外 - 您的 NSOperation 子類是否正確處理鍵值觀察? 並發隊列子類 NSOperations 必須為這里的某些屬性調用willChangeValueForKeydidChangeValueForKey - 但看起來不是問題,因為您的隊列沒有設置isConcurrent 如果你走那條路,僅供參考。

主線程的延遲是由於滾動時運行循環的模式。 我建議您觀看 WWDC2011 網絡應用程序會議。 我不知道將NSInvocationOperation子類化是否可以,它是NSOperation的具體子類。 我將NSOperation 根據我的經驗,如果您想避免緩慢滾動,您應該創建NSOperation子類,將它們的主要加載到特定線程以進行網絡操作(您必須創建它)。 蘋果有一個很棒的示例代碼https://developer.apple.com/library/ios/#samplecode/MVCNetworking/Introduction/Intro.html

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM