forceTouchCapability返回nil

时间:2015-12-16 17:23:40

标签: ios objective-c ios9 3dtouch

我正在尝试将一些3D触摸融入应用程序中,并且我遇到了一个奇怪的问题,forceTouchCapability检查在nil上返回viewDidLoad但在viewWillAppear/viewDidAppear中没有{1}}。

我知道这只适用于iOS 9+,因此我添加了检查以验证视图控制器上的traitCollection属性是否响应forceTouchCapability,如同以下内容:

- (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语句中有断点的LLDB中,输入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中添加这个,因为这可以调用很多。

如果有帮助,我会在iOS 9.1上使用Xcode 7.2在6S上运行它

3 个答案:

答案 0 :(得分:22)

视图尚未添加到视图层次结构中。您可以通过在调试控制台中检查超级视图来轻松查看此内容

(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 Touch设置,您的视图将会注册/取消注册。

答案 1 :(得分:1)

我也看到过这个问题,并发现检查设备是否可以支持强制触摸的最简单方法是通过屏幕实例进行操作。这有点意义,因为功能是屏幕的属性。这样做意味着您不必担心视图控制器或视图的生命周期。

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
}

答案 2 :(得分:-1)

就像@bpapa所说的那样,你的视图还没有添加到视图层次结构中,但我的解决方案有点不同:

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)
            }
        }
    }
}