1

共有ボタンがあるアプリがあります。私は、活動タイプに基づいて共有されるコンテンツをカスタマイズしたいと思います。たとえば、メッセージは画像とテキストを取得し、AirDropはファイルを取得します。このシナリオでは、UIActivityViewControllerが使用するアイテムをどのように変更できますか?

実際にこれは完全に機能しています。私が使用しているコードは、iOSのあらゆるバージョンでうまくいきました。しかし、私はどこにいなくてもどこにも戻っていないことを認識しました。それを修正する方法を見つけようとしています。

私は私の活動のビューコントローラをセットアップするには、このような何かを:

JUNActivityProvider *fileProvider = [[JUNActivityProvider alloc] initWithPlaceholderItem:[NSObject new]]; 
fileProvider.objectID = objectID; 
fileProvider.fileURL = fileURL; 

JUNActivityProvider *textProvider = [[JUNActivityProvider alloc] initWithPlaceholderItem:[NSString new]]; 
textProvider.objectID = objectID; 

... 

UIActivityViewController *activityController = [[UIActivityViewController alloc] 
    initWithActivityItems:@[fileProvider,imageProvider,textProvider,urlProvider,printFormatter] 
    applicationActivities:nil]; 

次にJUNActivityProviderで、私はactivityTypeに基づいて、戻り値をカスタマイズitem方法があります。

- (id)item { 

    if (self.fileURL) { 

     if ([self.activityType isEqualToString:UIActivityTypeAirDrop]) { 

      // Create the file 
      return url; 

     } 

    } else if ([self.placeholderItem isKindOfClass:[UIImage class]]) { 

     if ([self.activityType isEqualToString:UIActivityTypeAirDrop] == NO && 
      [self.activityType isEqualToString:UIActivityTypeMail] == NO && 
      [self.activityType isEqualToString:UIActivityTypePrint] == NO) { 

      // Create the image 
      return image; 

     } 

    } else if ([self.placeholderItem isKindOfClass:[NSString class]]) { 

     if ([self.activityType isEqualToString:UIActivityTypeMail]) { 

      return @"example one"; 

     } else if ([self.activityType isEqualToString:UIActivityTypeMessage] || 
      [self.activityType isEqualToString:UIActivityTypeCopyToPasteboard]) { 

      return @"example two"; 

     } 

    } 

    return nil; 

} 

を最後に返信return nilが問題です。それはうまく動作し、私が欲しいものを正確に行います。書かれたドキュメントは値を返さなければならないと言っていませんが、ヘッダファイルは以下を行います:

- (nonnull id)item; //ユーザがアクティビティを選択したときにセカンダリスレッドで呼び出されます。サブクラス化してnil以外の値を返す必要があります。

null以外の値が予想される場合は、nilを返すことでクラッシュする危険性がありません。この問題を解決する必要があります。私の唯一の選択肢は、UIActivityItemProviderの使用をやめ、代わりにUIActivityItemSourceプロトコルを自分で実装することです。複数の項目があれば、項目の一つは、実際の値を返すように、単一のアクティビティのタイプに対して登録された場合

はnilである場合があります。そのプロトコルは明らかにあなたがゼロリターンができると述べている方法activityViewController:itemForActivityType:を含み、 。

パーフェクト。しかしここに問題があります:activityViewController:itemForActivityType:がメインスレッドで呼び出され、特に私のアイテムの1つに問題を引き起こしています。ここには何が起こっているのかの概要があります:

  1. 私は非同期に実行するいくつかのメソッドを呼び出す必要があります。これを処理するために、ディスパッチセマフォを使用しようとしました。それは戻り値を設定する機会があるまでメソッドが返るのを防ぎます。
  2. activityViewController:itemForActivityType:がメインスレッドで呼び出されているので、そのスレッドが動作している間はロックされます。
  3. UIViewをイメージに描画する必要があります。メインスレッドでその作業をしようとすると、セマフォーがタイムアウトするまで何も起こりません。しかし、私がメインスレッドでそれをしないと、クラッシュします。

私はこれに対処する方法がありません。基本的に私は準備が整うまでメソッドを返さないようにする必要がありますが、そこでいくつかの作業を行う必要があるため、メインスレッドをロックすることはできません。これは不可能だ...この仕事をする方法はありますか?

+0

以前の試み(UIActivityItemProvider)から '[NSNull null]'を返してみましたか?これはオブジェクトであるという意味での "non-nil"戻り値ですが、ヌル/空の結果を示すためにCocoa APIでよく使用されています(UIActivityItemSourceを使用して他の場所で成功しました)。 – tgaul

+0

@tgaul : '[NSNull null]'を使うと 'nonnull'を満たし、問題を引き起こすように見えませんが、超緊張してしまいます - それが何をしているのか分かりませんオブジェクトがありません。何年も何も目立った問題が起きていないという理由だけで、 'nil'を固執する方が少し気になります。 – robotspacer

+0

' item'プロパティをnullableにすることを提案するバグレポートを提出しました:http: /www.openradar.me/radar?id=4563896690016256またはrdar:// 28394697 – robotspacer

答えて

3

enhancement requestを提出したあと、私はちょうどあきらめて、nilまたは[NSNull null]のいずれかを返していました。しかし、私は、この問題に対する絶対的な解決策があることを認識しました。

UIActivityItemProviderには独自の機能が多数含まれていますが、依然としてUIActivityItemSourceプロトコルが実装されています。私はそれを知っていた。私が考慮しなかったのは、これはちょうどactivityViewController:itemForActivityType:を無効にして、nilを返すことを意味します。適切な場合はです。

だから私のitem方法の最後の行は次のようになります。

return self.placeholderItem; 

あなたがここにも[NSNull null]を返す、または実際に任意のオブジェクトがあります。 placeholderItemを選択したのは、ちょっと安全だと思ったからです。少なくとも、実装について何か変更があった場合、予想される型のオブジェクトを返すことが分かっています。

それから私がしなければならないすべては(我々がnilを返すことが許さである)activityViewController:itemForActivityType:の私自身の実装を追加です:

- (nullable id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(UIActivityType)activityType { 
    id item = [super activityViewController:activityViewController itemForActivityType:activityType]; 
    if ([item isEqual:self.placeholderItem]) return nil; 
    return item; 
} 

はちょうどそれがあなた何かあればnilを返し、アイテムを取得するためにスーパーを呼び出しますそれが含まれている場合はアイテムを含めたり、返すことは望ましくありません。 placeholderItemが実際にはになる場合は、に共有したい場合は、この実装を少し変更する必要がありますが、同じ基本概念が有効であることに注意してください。

関連する問題