2017-12-19 6 views
0

私はiOS11の新しいAPIドラッグアンドドロップを学んでいますが、いくつか質問があります。 dataSource配列の同じタイプ(DataEntity)を共有する2つのcollectionViewがあります。 1つはドラッグ用で、もう1つはドロップ用です。つまり、データを含むアイテム(DataEntity)を1つのコレクションビューから別のコレクションビューにドラッグしたいということです。- [UIDragSession loadObjectsOfClass:completion:] completionBlockが呼び出されない

私は[-(id<UICollectionDropDelegate>)collectionView:performDropWithCoordinator:]に質問があります。 -[UIDragSession loadObjectsOfClass:completion:] completionBlockが呼び出されていないため、最初のcollectionViewで渡されたデータ(DataEntity)を取得できません。ただし、他のクラス(UIImage.classやNSString.classなど)をパラメータ​​に設定すると、補完ブロックが呼び出されますが、互換クラスではないため、戻りオブジェクトはありません。

ソースコード

ドラッグ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]; 
} 

ドロップcollectionView

- (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; 
} 

編集

[OK]をクリックします。 最初にdispatch_async(dispatch_get_main_queue())を削除すると、未確認のセレクタ - [DataEntity encodeWithCoder:]が表示されます。それは第二の事です、私は忘れてしまいますDataEntityに従います。NSCodingプロトコル。

今、新しい質問は、私がをdispatch_main_queueクロージャーにコールできないか、その完了ブロックが呼び出されないということです。

+0

あなたの 'objectWithItemProviderData'は呼び出されていますか? – matt

+0

@matt番号 'readableTypeIdentifiersForItemProvider'と 'writableTypeIdentifiersForItemProvider'が呼び出されます。 'loadDataWithTypeIdentifier'と 'objectWithItemProviderData'は呼び出されません。 – Tepmnthar

答えて

0

すべては非同期コード実行の基本原則と関係しています。 collectionView:performDropWithCoordinator:の実装では、このコードが間違っている:

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

あなたがdispatch_asyncを呼び出すときは、collectionView:performDropWithCoordinator:の呼び出しが戻ることを可能に - それは最後に来ます!しかし、あなたはの前にのデータを読み込みます。したがって、すぐにドロップが終了し、セッションが消えます。の前に、のデータを受け取る機会があります。 loadObjectsOfClassになると、データはなくなります。セッションはすでに終了しています。

実際には、sessionはその時点でnilであると確信しています。 nilオブジェクトに送信されたコードは何もしません。そのためあなたのobjectWithItemProviderDataと補完ハンドラは決して呼び出されません。

+0

あなたの答えをありがとう!それはかなり明確です。 – Tepmnthar

関連する問題