4

私はフィード リーダーに取り組んでおり、nsxmlparser を使用して RSS フィードを解析しています。CDATA ブロックから取得しているサムネイル オブジェクトもあります。

-(void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
    NSString *storyImageURL = [self getFirstImageUrl:someString];

    NSURL *tempURL = [NSURL URLWithString:storyImageURL];

    NSData *tempData = [NSData dataWithContentsOfURL:tempURL];
    thumbnail = [UIImage imageWithData:tempData];

    });
}

アーカイブおよびエンコードとデコードのメソッドを使用して、画像やその他のテーブルビュー オブジェクトを永続化しています。

問題は、上記のコードをそのまま使用すると、画像が保持されず、タイトルや公開日などの他のテーブルビュー オブジェクトが保持されることです。しかし、dispatch_async を使用せずに上記のコードを使用すると、イメージの永続化が開始されますが、ユーザー インターフェイスがロックされます。

ユーザー インターフェイスをロックせずに画像を保持するにはどうすればよいですか?

画像を保存およびキャッシュするためのライブラリや、Apple の遅延読み込みの例については回答しないでください。ありがとう

アップデート:

提供された回答に基づいて、iTunes でマルチスレッドに関するスタンフォードの講義を見た後、上記のコードを次のように実装しました。

  NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
    NSString *storyImageURL = [self getFirstImageUrl:someString];
    NSURL *tempURL = [NSURL URLWithString:storyImageURL];

    dispatch_queue_t downloadQueue = dispatch_queue_create("image downloader", NULL);

    dispatch_async(downloadQueue, ^{
        NSData *tempData = [NSData dataWithContentsOfURL:tempURL];

        dispatch_async(dispatch_get_main_queue(), ^{
            thumbnail = [UIImage imageWithData:tempData];
        });
    });
}

論理的には、すべてが正しいものになりましたが、それでも機能しませんでした。この問題を解決する方法はすべてブロックされています。

アップデート:

Model View Controller Store アプローチを使用しており、ストアと接続コードは別のファイルで定義されています。以下は、NSKeyedArchiver を使用しているコードです。

- (FeedChannel *) FeedFetcherWithCompletion:(void (^)(FeedChannel *, NSError *))block {

    NSURL *url = [NSURL URLWithString:@"http://techcrunch.com/feed/"];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];

    FeedChannel *channel = [[FeedChannel alloc] init];

    TheConnection *connection = [[TheConnection alloc] initWithRequest:req];

    NSString *pathOfCache = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    pathOfCache = [pathOfCache stringByAppendingPathComponent:@"check.archive"];

    FeedChannel *channelCache = [NSKeyedUnarchiver unarchiveObjectWithFile:pathOfCache];


    if (!channelCachel) {
        channelCache = [[FeedChannel alloc] init];
    }
    FeedChannel *channelCopy = [channelCache copy];

    [connection setCompletionBlock:^(FeedChannel *obj, NSError *err) {
        if (!err) {
            [channelCopy addItemsFromChannel:obj];
            [NSKeyedArchiver archiveRootObject:channelCopy toFile:pathOfCache];
        }
        block(channelCopy, err);
    }];

    [connection setXmlObject:channel];
    [connection start];

    return channelCache;
}

以下は私のエンコードとデコードの方法です。

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:title forKey:@"title"];
    [aCoder encodeObject:link forKey:@"link"];
    [aCoder encodeObject:creator forKey:@"creator"];
    [aCoder encodeObject:pubDate forKey:@"pubDate"];
    [aCoder encodeObject:thumbnail forKey:@"thumbnail"];
    //[aCoder encodeObject:UIImagePNGRepresentation(thumbnail) forKey:@"thumbnail"];
    [aCoder encodeObject:publicationDate forKey:@"publicationDate"];

}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super init];
    if (self)
    {
        [self setTitle:[aDecoder decodeObjectForKey:@"title"]];
        [self setLink:[aDecoder decodeObjectForKey:@"link"]];
        [self setCreator:[aDecoder decodeObjectForKey:@"creator"]];
        [self setPubDate:[aDecoder decodeObjectForKey:@"pubDate"]];
        [self setThumbnail:[aDecoder decodeObjectForKey:@"thumbnail"]];
        //[self setThumbnail:[UIImage imageWithData:[aDecoder decodeObjectForKey:@"thumbnail"]]];
        [self setPublicationDate:[aDecoder decodeObjectForKey:@"publicationDate"]];

    }
    return self;
}

答えに基づいて、画像を永続化するために追加のコードを使用する必要があるかどうかわかりません。タイトル、作成者などの他のオブジェクトが正確に永続化されているためです。

4

1 に答える 1

5

コメントを読んだ後、問題は、dispatch_asyncブロックに関連する画像をどのように永続化するかに関係していると思う傾向があります。説明しようとしますが、画像をどこに永続化するかわからないため、これは単なる推測です。

  1. ある時点であなたparser:foundCDATA:は実行され、非同期で画像を取得します。

  2. イメージはしばらくの間(同期ブロックが完了するまで)存在しないため、thumbnail完了後しばらくの間、ivar/propertyは正しい値を持ちませんparser:foundCDATA:

  3. ここでthumbnail、非同期ブロックが完了する前に永続化すると、間違った(nil?)値が永続化されます。

  4. 画像のフェッチを非同期で実行しないと、すべてが機能するという事実から、画像の永続化が早すぎると思います(上記の意味で)。

これに対する修正は、非同期ブロックが完了した後にのみイメージを永続化することです。これは、次のような意味になる可能性があります。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

  NSString *someString = [[NSString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];
  NSString *storyImageURL = [self getFirstImageUrl:someString];

  NSURL *tempURL = [NSURL URLWithString:storyImageURL];

  NSData *tempData = [NSData dataWithContentsOfURL:tempURL];
  thumbnail = [UIImage imageWithData:tempData];

  <code here to make the thumbnail be persisted>

});

<code here to make the thumbnail be persisted>現在のデザインに合うものなら何でも、メソッド呼び出し、通知投稿である可能性があります。永続化コードがスレッドセーフでない場合は、メインスレッドに呼び出しをディスパッチするトリックを使用する必要がある場合もあります。

  dispatch_async(dispatch_get_main_queue(), ^{
      <persist thumbnail>;
  }

それが役に立てば幸い。

編集:

チャットの後、上記の分析が確認されました。実際、あなたは単に1つの画像をダウンロードしているのではなく、すべて同じ「チャネル」に属する多数の画像をダウンロードしているのです。これは、チャネル全体に適用される永続化操作は、それらのすべてのイメージがダウンロードされた後にのみ実行されることを意味します。

このように、私はあなたの要点をフォークし、GCDdispatch_groupを使用してすべてのダウンロード操作を追跡できるようにするいくつかのロジックを追加しました。ここで見つけることができます。

于 2013-01-17T21:45:09.953 に答える