首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >-[UIDragSession加载对象completion:completion:] completionBlock未被调用

-[UIDragSession加载对象completion:completion:] completionBlock未被调用
EN

Stack Overflow用户
提问于 2017-12-19 04:28:03
回答 1查看 791关注 0票数 0

我正在学习iOS11新API的拖放,但我有一些问题。我有两个collectionViews,它们共享dataSource数组的相同类型(、DataEntity、)。一个是用来拖的,另一个是用来拖的。这意味着我希望将包含数据的项(DataEntity)从一个collectionView拖到另一个collectionView。

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

源代码

拖动collectionView

代码语言:javascript
复制
- (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];
}

滴下collectionView

代码语言:javascript
复制
- (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;
}

数据实体

代码语言:javascript
复制
- (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:],或者它的完成块不会被调用?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-12-19 13:07:58

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

代码语言:javascript
复制
dispatch_async(dispatch_get_main_queue(), ^{
    [coordinator.session loadObjectsOfClass: // ...

当您调用dispatch_async时,您允许返回对collectionView:performDropWithCoordinator:的调用--它即将结束!但是,在继续加载数据之前,您正在这样做。因此,在您有机会获取数据之前,下降会立即结束,会话将消失。当我们到达loadObjectsOfClass时,就没有数据了;会话已经结束了。

事实上,我打赌session在那一点上是nil。发送给nil对象的代码什么也不做;这就是为什么您的objectWithItemProviderData和完成处理程序从未被调用的原因。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47880026

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档