2015-12-16 13 views
6

nilを返します。forceTouchCapabilityは、私は、アプリケーションにいくつかの3Dタッチを組み込むしようとしていると私は<code>forceTouchCapability</code>チェックが<code>viewDidLoad</code>ではなく<code>viewWillAppear/viewDidAppear</code>で<code>nil</code>を返している奇妙な問題に遭遇しました

私はこれが9+ので、私は、ビューコントローラのtraitCollectionプロパティは、次のようにforceTouchCapabilityに応答することを確認するためのチェックを追加しましたiOS版でのみ利用可能であることを承知している:

LLDBで
- (void)loadView { 

    self.view = [[MyView alloc] init]; 
} 

- (void)viewDidLoad { 

    [super viewDidLoad]; 

    // Checking the force touch availability here 
    if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)] && 
     self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) { 

     // This won't get called because forceTouchCapability is returning nil 
     // which corresponds to UIForceTouchCapabilityUnknown 
     [self registerForPreviewingWithDelegate:self sourceView:self.view]; 
    } 
} 

ifステートメントのブレークポイントでは、po [self.traitCollection forceTouchCapability]と入力するとnilが返され、これはUIForceTouchCapabilityUnknownに対応します。ただし、traitCollection自体はnilではありません。

はUIForceTouchCapabilityUnknownのドキュメントによると:

UIForceTouchCapabilityUnknown: The availability of 3D Touch is unknown. For example, if you create a view but have not yet added it to your app’s view hierarchy, the view’s trait collection has this value.

ビューは、この時点で階層に追加されていませんか?

誰もがこの問題に遭遇し、これを回避する方法が不思議ですか?私はviewDidAppearにこれを追加することを避けたいと思います。それが助け場合

、私は、ビューはまだビュー階層に追加されていないのXcode 7.2

答えて

16

でのiOS 9.1に6S上でこれを実行していますよ。あなたはそれはあなたが見ているものだと、ビューはまだ階層に追加されていないデバッグコンソールにスーパーのため

(lldb) po self.view.superview 
nil 

をチェックすることでこれを簡単に見ることができますので、あなたは他の場所であなたの小切手を配置する必要があります。

これは、AppleのViewControllerPreviewサンプルアプリケーションではviewDidLoadにあるため、混乱します。しかし、本当にtraitCollectionDidChange:にする必要があります。なぜなら、ビューがアプリケーションの階層に追加されているからです。

これは私が使用するコードです(外側の条件を自由に移動できるようにする必要がない場合は、iOS 8で動作します)。

- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { 
    [super traitCollectionDidChange:previousTraitCollection]; 

    if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)]) { 
     if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) { 
      // retain the context to avoid registering more than once 
      if (!self.previewingContext) { 
       self.previewingContext = [self registerForPreviewingWithDelegate:self sourceView:self.view]; 
      } 
     } else { 
      [self unregisterForPreviewingWithContext:self.previewingContext]; 
      self.previewingContext = nil; 
     } 
    } 
} 

これに追加された利点は、アプリケーションの実行中に、ユーザーが自分の3Dタッチの設定を変更した場合、あなたのビューが登録されていない/登録されるということです。

+0

あなたは素晴らしいです、ありがとう! – ajfigueroa

+0

@bpapa良い解決策。 poの代わりにpの使用法を推薦することを検討してください。 pはちょうど内側にあり、poは実行に使用されます –

1

この問題もあり、デバイスが強制接触をサポートできるかどうかを確認する最も簡単な方法は、画面インスタンスを介してデバイスを操作することです。この機能は画面のプロパティなので、これはちょっと意味があります。このようにすると、ビューコントローラーやビューのライフサイクルについて心配する必要がなくなります。 @bpapaが言ったよう

func canForceTouch() -> Bool 
{ 
    if iOS9OrHigher // pseudocode, a function that makes sure u only do this check on ios9 or higher 
    { 
     return UIScreen.mainScreen().traitCollection.forceTouchCapability == .Available 
    } 
    return false 
} 
0

、あなたのビューは、階層ビューに追加されていない、まだ、しかし、私の解決策は、異なる少しです:

var token:dispatch_once_t = 0 
override func viewDidAppear(animated: Bool) { 
    dispatch_once(&token) { 
     // Force Touch Checking 
     if #available(iOS 9.0, *) { 
      if self.traitCollection.forceTouchCapability == .Available { 
       self.registerForPreviewingWithDelegate(self, sourceView: self.view) 
      } 
     } 
    } 
} 
+0

これに異なるキューを入れるのはなぜですか?実際には、オプションのメソッドを実装してSDKに準拠させることは、はるかにクリーンなアプローチです。 – bpapa

+0

@bpapa私たちはまだメインキュー(この回答を参照してくださいhttp://stackoverflow.com/a/25900466参照)を使用しています...すべてのビューが階層内にあることを確認するには、このコードをviewDidAppearで記述しています。一度viewDidAppearが何度も呼び出される可能性があるので、あなたはそれを知っています:) – Husam

関連する問題

 関連する問題