簡體   English   中英

-[UIDragSession loadObjectsOfClass:completion:]完成塊未調用

[英]-[UIDragSession loadObjectsOfClass:completion:] completionBlock not being called

我正在學習iOS11的新API拖放,但是我有一些疑問。 我有兩個collectionViews,它們共享相同類型的dataSource數組( DataEntity )。 一個用於拖動,另一個用於拖放。 這意味着我想將包含數據( DataEntity )的項目從一個collectionView拖到另一個。

然后我在[-(id<UICollectionDropDelegate>)collectionView:performDropWithCoordinator:] 我無法獲取在我的第一個collectionView中傳遞的數據( DataEntity ),因為未調用-[UIDragSession loadObjectsOfClass:completion:] 但是,如果我將其他類(例如UIImage.class或NSString.class)設置為參數loadObjectsOfClass:則會調用完成塊,但是它不是兼容類,因此沒有返回對象。

源代碼

拖動collectionView

- (NSArray<UIDragItem *> *)collectionView:(UICollectionView *)collectionView itemsForBeginningDragSession:(id<UIDragSession>)session atIndexPath:(NSIndexPath *)indexPath {

    DataEntity* entity = self.entities[indexPath.row];
    UIDragItem* item = [[UIDragItem alloc] initWithItemProvider:[[NSItemProvider alloc] initWithObject:entity]];
    return @[item];
}

下降收集視圖

- (void)collectionView:(UICollectionView *)collectionView performDropWithCoordinator:(id<UICollectionViewDropCoordinator>)coordinator {
    NSIndexPath* destinationIndexPath = coordinator.destinationIndexPath;
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.collectionView performBatchUpdates:^{
            [coordinator.session loadObjectsOfClass:DataEntity.class completion:^(NSArray<__kindof id<NSItemProviderReading>> * _Nonnull objects) {
                [objects enumerateObjectsUsingBlock:^(__kindof id<NSItemProviderReading>  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                    [self.mutableEntities insertObject:(DataEntity*)obj atIndex:destinationIndexPath.row];
                    [self.collectionView insertItemsAtIndexPaths:@[destinationIndexPath]];
                }];
            }];
        } completion:nil];
    });
}
- (BOOL)collectionView:(UICollectionView *)collectionView canHandleDropSession:(id<UIDropSession>)session {
    BOOL test = [session canLoadObjectsOfClass:DataEntity.class]; // It's YES
    return test;
}

數據實體

- (NSProgress *)loadDataWithTypeIdentifier:(NSString *)typeIdentifier forItemProviderCompletionHandler:(void (^)(NSData * _Nullable, NSError * _Nullable))completionHandler {
    NSData* data = [NSKeyedArchiver archivedDataWithRootObject:self];
    completionHandler(data, nil);
    return nil;
}
+ (NSArray<NSString *> *)writableTypeIdentifiersForItemProvider {
    NSString* identifier = NSStringFromClass(self.class);
    return @[identifier];
}
+ (NSArray<NSString *> *)readableTypeIdentifiersForItemProvider {
    NSString* identifier = NSStringFromClass(self.class);
    return @[identifier];
}
+ (nullable instancetype)objectWithItemProviderData:(nonnull NSData *)data typeIdentifier:(nonnull NSString *)typeIdentifier error:(NSError * _Nullable __autoreleasing * _Nullable)outError {
    DataEntity* entity = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    return entity;
}

編輯

好的,我發現了一些東西。 首先,如果刪除dispatch_async(dispatch_get_main_queue()) ,我將得到一個錯誤的無法識別的選擇器-[DataEntity encodeWithCoder:] 那是第二件事,我忘記使DataEntity符合NSCoding協議。

現在,新問題是,為什么我不能在dispatch_main_queue閉包中調用-[UIDragSession loadObjectsOfClass:completion:] ,否則將不會調用其完成塊?

所有這些都與異步代碼執行的基本原理有關。 在您的collectionView:performDropWithCoordinator:實現中,此代碼是錯誤的:

dispatch_async(dispatch_get_main_queue(), ^{
    [coordinator.session loadObjectsOfClass: // ...

當您調用dispatch_async ,您允許對collectionView:performDropWithCoordinator:的調用返回—它結束了! 但是您要先進行此操作, 然后再繼續加載數據。 因此, 您有機會提取數據之前 ,刪除操作立即結束,會話消失。 當我們進入loadObjectsOfClass ,就不再有數據了。 會話已經結束。

實際上,我打賭那時的sessionnil 發送到nil對象的代碼什么也沒有做。 這就是為什么從不調用objectWithItemProviderData和完成處理程序的原因。

暫無
暫無

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

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