2015-07-05 1 views
1

У меня есть приложение с коллекцией изображений, которые вытаскиваются из CloudKit. У меня есть класс CKManager, который выполняет все связанные с CK методы. В viewcontroller я вызываю метод в CKManager для извлечения исходных данных из CK, который работает отлично. Я использую CKQueryOperation, поэтому я могу вытащить данные в блоках, хотя до сих пор я настраивал ckQueryOperation.resultsLimit = CKQueryOperationMaximumResults только для тестирования. В результате при прокрутке коллекции, изображения/ячейки не «исчезают» при прокрутке. Я предполагаю, что это происходит потому, что все данные были получены до рендеринга ячеек. В настоящее время существует около 50 записей, и он загружается довольно быстро, но он определенно загружается быстрее, когда я устанавливаю предел результатов, например, 25.Загрузить UICollectionView с помощью курсора

Моя проблема в том, что я не совсем понимаю, как это сделать, используя курсор, хотя я уже планировал это, внедряя курсор в свой код. Я нашел этот thread, который я понял для большей части, но он в Swift, и он также не отвечает на все мои вопросы. Я изменил свой код на основе ответа Эдвина в этом потоке, но я уверен, что мне не хватает чего-то в переводе Swift на OB-C.

Ниже приведен код, который я вызываю в своем классе CKManager. Я вижу из журнала, что он работает правильно и распознает курсор. Я не понимаю, как/когда я снова его вызываю, чтобы получить следующий блок результатов из этой точки курсора? Если результатLimit не установлен как максимальный, как и изначально, я получаю количество заданных результатов (20), и оно не извлекает оставшиеся. Поэтому я не знаю, как получить оставшиеся результаты, когда курсор остановился. Я знаю, что, поскольку я использую collectionview, мне нужно будет обновлять количество элементов в разделе каждый раз, когда получаю следующий блок результатов.

Большое спасибо!

ОБНОВЛЕНО: Измененное loadCloudKitDataWithCompletionHandler добавить вызов нового метода принятия курсора - loadCloudKitDataFromCursor: withCompletionHandler :. Единственное, чего не хватает, - это выяснить, где в ViewController обрабатывать результаты, возвращаемые методом с помощью курсора, для обновления numberOfItemsInSection, а затем перезагрузить CollectionView.

От CKManager ...

- (void)loadCloudKitDataFromCursor:(CKQueryCursor *)cursor withCompletionHandler:(void (^)(NSArray *, CKQueryCursor *, NSError *))completionHandler { 
    NSMutableArray *cursorResultSet = [[NSMutableArray alloc] init]; 
    __block NSArray *results; 

    if (cursor) { // make sure we have a cursor to continue from 
     NSLog(@"INFO: Preparing to load records from cursor..."); 
     CKQueryOperation *cursorOperation = [[CKQueryOperation alloc] initWithCursor:cursor]; 
     cursorOperation.resultsLimit = 20; 

     // processes for each record returned 
     cursorOperation.recordFetchedBlock = ^(CKRecord *record) { 
      NSLog(@"RecordFetchBlock returned from cursor CID record: %@", record.recordID.recordName); 
      [cursorResultSet addObject:record]; 
     }; 
     // query has completed 
     cursorOperation.queryCompletionBlock = ^(CKQueryCursor *cursor, NSError *error) { 
      results = [cursorResultSet copy]; 
      [cursorResultSet removeAllObjects]; // get rid of the temp results array 
      completionHandler(results, cursor, error); 
      if (cursor) { 
       NSLog(@"INFO: Calling self to fetch more data from cursor point..."); 
       [self loadCloudKitDataFromCursor:cursor withCompletionHandler:^(NSArray *results, CKQueryCursor *cursor, NSError *error) { 
        results = [cursorResultSet copy]; 
        [cursorResultSet removeAllObjects]; // get rid of the temp results array 
        completionHandler(results, cursor, error); 
       }]; 
      } 
     }; 

     [self.publicDatabase addOperation:cursorOperation]; 
    } 

} 

- (void)loadCloudKitDataFromCursor:(CKQueryCursor *)cursor withCompletionHandler:(void (^)(NSArray *, CKQueryCursor *, NSError *))completionHandler { 
    NSMutableArray *cursorResultSet = [[NSMutableArray alloc] init]; 
    __block NSArray *results; 

    if (cursor) { // make sure we have a cursor to continue from 
     NSLog(@"INFO: Preparing to load records from cursor..."); 
     CKQueryOperation *cursorOperation = [[CKQueryOperation alloc] initWithCursor:cursor]; 
     cursorOperation.resultsLimit = 20; 

     // processes for each record returned 
     cursorOperation.recordFetchedBlock = ^(CKRecord *record) { 
      NSLog(@"RecordFetchBlock returned from cursor CID record: %@", record.recordID.recordName); 
      [cursorResultSet addObject:record]; 
     }; 
     // query has completed 
     cursorOperation.queryCompletionBlock = ^(CKQueryCursor *cursor, NSError *error) { 
      results = [cursorResultSet copy]; 
      [cursorResultSet removeAllObjects]; // get rid of the temp results array 
      completionHandler(results, cursor, error); 
      if (cursor) { 
       NSLog(@"INFO: Calling self to fetch more data from cursor point..."); 
       [self loadCloudKitDataFromCursor:cursor withCompletionHandler:^(NSArray *results, CKQueryCursor *cursor, NSError *error) { 
        results = [cursorResultSet copy]; 
        [cursorResultSet removeAllObjects]; // get rid of the temp results array 
        completionHandler(results, cursor, error); 
       }]; 
      } 
     }; 

     [self.publicDatabase addOperation:cursorOperation]; 
    } 

} 

Изнутри метода ViewController который вызывает CKManager, чтобы получить данные ...

dispatch_async(queue, ^{ 
     [self.ckManager loadCloudKitDataWithCompletionHandler:^(NSArray *results, CKQueryCursor *cursor, NSError *error) { 
      if (!error) { 
       if ([results count] > 0) { 
        self.numberOfItemsInSection = [results count]; 
        NSLog(@"INFO: Success querying the cloud for %lu results!!!", (unsigned long)[results count]); 
        [self loadRecipeDataFromCloudKit]; // fetch the recipe images from CloudKit 
        // parse the records in the results array 
        for (CKRecord *record in results) { 
         ImageData *imageData = [[ImageData alloc] init]; 
         CKAsset *imageAsset = record[IMAGE]; 
         imageData.imageURL = imageAsset.fileURL; 
         imageData.imageName = record[IMAGE_NAME]; 
         imageData.imageDescription = record[IMAGE_DESCRIPTION]; 
         imageData.userID = record[USER_ID]; 
         imageData.imageBelongsToCurrentUser = [record[IMAGE_BELONGS_TO_USER] boolValue]; 
         imageData.recipe = [record[RECIPE] boolValue]; 
         imageData.liked = [record[LIKED] boolValue]; // 0 = No, 1 = Yes 
         imageData.recordID = record.recordID.recordName; 
         // check to see if the recordID of the current CID is userActivityDictionary. If so, it's in the user's private 
         // data so set liked value = YES 
         if ([self.imageLoadManager lookupRecordIDInUserData:imageData.recordID]) { 
          imageData.liked = YES; 
         } 
         // add the CID object to the array 
         [self.imageLoadManager.imageDataArray addObject:imageData]; 

         // cache the image with the string representation of the absolute URL as the cache key 
         if (imageData.imageURL) { // make sure there's an image URL to cache 
          if (self.imageCache) { 
           [self.imageCache storeImage:[UIImage imageWithContentsOfFile:imageData.imageURL.path] forKey:imageData.imageURL.absoluteString toDisk:YES]; 
          } 
         } else { 
          NSLog(@"WARN: CID imageURL is nil...cannot cache."); 
          dispatch_async(dispatch_get_main_queue(), ^{ 
           //[self alertWithTitle:@"Yikes!" andMessage:@"There was an error trying to load the images from the Cloud. Please try again."]; 
           UIAlertView *reloadAlert = [[UIAlertView alloc] initWithTitle:YIKES_TITLE message:ERROR_LOADING_CK_DATA_MSG delegate:nil cancelButtonTitle:CANCEL_BUTTON otherButtonTitles:TRY_AGAIN_BUTTON, nil]; 
           reloadAlert.delegate = self; 
           [reloadAlert show]; 
          }); 
         } 
        } 
        // update the UI on the main queue 
        dispatch_async(dispatch_get_main_queue(), ^{ 
         // enable buttons once data has loaded... 
         self.userBarButtonItem.enabled = YES; 
         self.cameraBarButton.enabled = YES; 
         self.reloadBarButton.enabled = YES; 

         if (self.userBarButtonSelected) { 
          self.userBarButtonSelected = !self.userBarButtonSelected; 
          [self.userBarButtonItem setImage:[UIImage imageNamed:USER_MALE_25]]; 
         } 
         [self updateUI]; // reload the collectionview after getting all the data from CK 
        }); 
       } 
       // load the keys to be used for cache look up 
       [self getCIDCacheKeys]; 
      } else { 
       NSLog(@"Error: there was an error fetching cloud data... %@", error.localizedDescription); 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        //[self alertWithTitle:@"Yikes!" andMessage:@"There was an error trying to load the images from the Cloud. Please try again."]; 
        UIAlertView *reloadAlert = [[UIAlertView alloc] initWithTitle:YIKES_TITLE message:ERROR_LOADING_CK_DATA_MSG delegate:nil cancelButtonTitle:CANCEL_BUTTON otherButtonTitles:TRY_AGAIN_BUTTON, nil]; 
        reloadAlert.delegate = self; 
        [reloadAlert show]; 
       }); 
      } 
     }]; 
    } 

ответ

1

Вы близки. Для newOperation вам также необходимо установить recordFetchedBlock и queryCompletionBlock. Когда вы назначаете новую операцию операции и выполняете ее, вы не потеряете ссылку, и ваш код будет продолжать работать. Замените одну строку [self.publicDatabase addOperation: newOperation]; с:

newOperation.recordFetchedBlock = operation.recordFetchedBlock 
newOperation.queryCompletionBlock = operation.queryCompletionBlock 
operation = newOperation 
[self.publicDatabase addOperation:operation]; 
+0

Еще раз спасибо Эдвин! Ты мне помог много раз! Однако есть проблемы с вашим кодом. Откуда происходит «операция»? Он не определен ранее в вашем коде или в моем. Я подумал, может быть, вы используете ckQueryOperation из моего кода выше, но это тоже не сработало. Поскольку я все еще немного в темноте, я не могу изменить его правильно самостоятельно. Благодаря! – SonnyB

+0

Ах, извините, скопируйте ошибку патча. В вашем случае это должно быть ckQueryOperation –

+0

Я предположил, что, возможно, это то, что вы имеете в виду, поэтому я попробовал это, и он не сработал. Получено предупреждение о newOperation.recordFetchedBlock = ckQueryOperation.recordFetchedBlock; (может привести к циклу сохранения) и ошибке на ckQueryOperation = newOperation; поскольку они не могут быть назначены в блоке. Я разрешил ошибку, добавив __block в объявление ckQueryOperation выше, но не уверен, что я должен делать с предупреждением о сохранении цикла. – SonnyB

 Смежные вопросы

  • Нет связанных вопросов^_^