代码之家  ›  专栏  ›  技术社区  ›  Tepmnthar

-[UIDragSession loadObjectsOfClass:completion:]未调用completionBlock

  •  0
  • Tepmnthar  · 技术社区  · 7 年前

    我正在学习iOS11新的API拖放,但我有一些问题。 我有两个CollectionView,它们共享相同的类型( 数据实体 )数据源数组的。一个用于拖动,另一个用于拖放。这意味着我要拖动包含数据的项( 数据实体 )从一个集合视图到另一个集合视图。

    那我有问题了 [-(id<UICollectionDropDelegate>)collectionView:performDropWithCoordinator:] . 我无法获取数据( 数据实体 )在我的第一个collectionView中通过,因为 -[UIDragSession loadObjectsOfClass:completion:] 未调用completionBlock。但是,如果我将其他类(如UIImage.class或NSString.class)设置为参数 loadObjectsOfClass: 将调用完成块,但它不是兼容类,因此没有返回对象。

    源代码

    拖动集合视图

    - (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:] . 这是第二件事,我忘了 数据实体 符合 N编码 协议

    现在的新问题是,为什么我不能打电话 -[UIDragSession loadObjectsOfClass:完成:] 在里面 dispatch\u main\u队列 闭包,还是不调用其完成块?

    1 回复  |  直到 7 年前
        1
  •  1
  •   matt    7 年前

    这一切都与异步代码执行的基本原则有关。在您的实施中 collectionView:performDropWithCoordinator: ,此代码错误:

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

    当你打电话的时候 dispatch_async ,您允许呼叫 集合视图:performDropWithCoordinator: 回来吧,一切都结束了!但你正在这么做 之前 继续加载数据。因此,丢弃立即结束,会话消失, 之前 您有机会获取数据。当我们到达 loadObjectsOfClass ,不再有数据;会话已结束。

    事实上,我打赌 session 在这一点上 nil . 和代码发送到 对象不做任何事情;这就是为什么你 objectWithItemProviderData 并且从不调用完成处理程序。