2

Paul Hegarty のコース CS193P から課題 6を完了しようとしています。つまり、これは Flickr からダウンロードした写真を閲覧するための iOS アプリケーションです。アプリケーションには 2 つのタブがあります。

  • 最初のタブは、タグで写真を閲覧するために使用されます。タグをクリックすると、このタグが設定された写真が一覧表示されます。写真をクリックすると表示されます。これらはすべて、Navigation Controller に埋め込まれた Table View と、最後に表示用の UIScrollView によって実現されます。
  • 2 番目のタブは、テーブル ビューで最近表示した写真を参照するために使用されます。

写真とタグ情報は Core Data に保存されます。このデータは、 を通じてテーブルに表示されますNSFetchedResultsController

ここに私の問題があります: Core Data オブジェクトを更新しない限り、すべて問題ありません。オブジェクトを更新すると (たとえば、写真に lastViewed プロパティを設定して [最近] タブに表示できるようにする)、次のテーブル ビューの更新時に、対応する写真が Flickr から再度ダウンロードされます。テーブル ビュー。長いデバッグ セッションの後、ようやく問題を発見しましたが、その理由を説明することはできません。これは、明示的に変更を保存せずに Core Data オブジェクトを更新したためです。

Core Data Programming Guideとさまざまな Class Reference ドキュメントを読みましたが、これに関する答えを見つけることができませんでした。

ユーザーが表示したいときに Photo lastViewed プロパティを更新するコードを次に示します。行のコメントを外すと[[SharedDocument sharedInstance] saveDocument]、すべてが期待どおりに機能します。コメントすると、表示された写真は次の更新時に再度ダウンロードされますが、Core Data には既に存在します。

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];

    // - Variable check discarded for a readability purpose -

    if ([segue.identifier isEqualToString:@"setImageURL:"])
    {
        Photo *photo = [self.fetchedResultsController objectAtIndexPath:indexPath];

        // Update the last viewed date property to now
        photo.lastViewed = [NSDate dateWithTimeIntervalSinceNow:0];

        // If I uncomment the line below, the issue disappears:
        // [[SharedDocument sharedInstance] saveDocument];

        if ([segue.destinationViewController respondsToSelector:@selector(setImageURL:)])
        {
            // Prepare the next VC
        }
    }
}

NSManagedObjectContext共有されます。共有オブジェクトのコードは次のとおりです。

@interface SharedDocument()
@property (strong, nonatomic)  UIManagedDocument * document;
@end

@implementation SharedDocument

+ (SharedDocument *) sharedInstance
{...} // Returns the shared instance

- (UIManagedDocument *) document
{...} // Lazy instantiation

- (void) useDocumentWithBlock:(void (^)(BOOL success))completionHandler
{...} // Create or open the document

- (void) saveDocument
{
    [self.document saveToURL:self.document.fileURL
            forSaveOperation:UIDocumentSaveForOverwriting
           completionHandler:nil];
}

アップデート:

Flickr の写真に関する注意: Flickr から 50 枚の写真をダウンロードできます。これは有限のセットです。つまり、新しい写真が追加または更新されることはありません。そのため、テーブル ビューを更新しても、新しい写真はダウンロードされません。

Photo オブジェクトは次のように作成されます (これはNSManagedObjectサブクラスのカテゴリです)。

+ (Photo *) photoWithFlickrInfo:(NSDictionary *)photoDictionary
         inManagedObjectContext:(NSManagedObjectContext *)context
{    
    Photo * photo = nil;

    // Check whether the photo already exists
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Photo"];
    NSString *pred = [NSString stringWithFormat:@"uniqueId = %@",
                      [photoDictionary[FLICKR_PHOTO_ID] description]];
    request.predicate = [NSPredicate predicateWithFormat:pred];
    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"uniqueId"
                                                                     ascending:YES];
    request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

    NSError *error = nil;

    NSArray *matches = [context executeFetchRequest:request error:&error];

    if (!matches || ([matches count] > 1) || error)
    {
        // Abnormal
        NSLog(@"Error accessing database: %@ (%d matches)", [error description], [matches count]);
    }
    else if (0 == [matches count])
    {
        // Create the photo
        photo = [NSEntityDescription insertNewObjectForEntityForName:@"Photo"
                                              inManagedObjectContext:context];

        photo.uniqueId = photoDictionary[FLICKR_PHOTO_ID];
        photo.title    = [photoDictionary[FLICKR_PHOTO_TITLE] description];
        photo.comment  = [[photoDictionary valueForKeyPath:FLICKR_PHOTO_DESCRIPTION] description];

        if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
        {
            photo.imageURL = [[FlickrFetcher urlForPhoto:photoDictionary
                                                  format:FlickrPhotoFormatOriginal] absoluteString];
        }
        else
        {
            // iPhone
            photo.imageURL = [[FlickrFetcher urlForPhoto:photoDictionary
                                                  format:FlickrPhotoFormatLarge] absoluteString];

        }

        photo.thumbnailURL = [[FlickrFetcher urlForPhoto:photoDictionary
                                                  format:FlickrPhotoFormatSquare] absoluteString];

        photo.section = [photo.title substringToIndex:1];

        // Update the category / tag
        for (NSString * category in [photoDictionary[FLICKR_TAGS] componentsSeparatedByString:@" "])
        {            
            // Ignore a couple of categories
            if ([@[@"cs193pspot", @"portrait", @"landscape"] containsObject:[category lowercaseString]])
                continue;

            Tag *tag = [Tag withName:[category capitalizedString] forPhoto:photo inManagedObjectContext:context];

            [photo addTagsObject:tag];
        }

        NSArray *allTags = [[photo.tags allObjects] sortedArrayUsingComparator:^NSComparisonResult(Tag * t1, Tag * t2) {
            return [t1.name compare:t2.name];
        }];

        photo.tagString = ((Tag *) [allTags objectAtIndex:0]).name;
        NSLog(@"PhotoTagString: %@", photo.tagString);

        // Update the specific 'All' tag
        Tag * allTag = [Tag withName:@"All" forPhoto:photo inManagedObjectContext:context];
        [photo addTagsObject:allTag];

        NSLog(@"[CORE DATA] Photo created: %@ with %d tags", photo.uniqueId, [photo.tags count]);
    }
    else
    {
        // Only one entry
        photo = [matches lastObject];

        NSLog(@"[CORE DATA] Photo accessed: %@", photo.uniqueId);
    }

    return photo;
}

私の説明が十分に明確であることを願っています。この問題を理解するためにさらに情報が必要な場合は教えてください (これは私の最初の投稿です。私はまだ若いパダワンです :-)

事前にどうもありがとう、

フロリアン

4

1 に答える 1