forceTouchCapability 返回零
forceTouchCapability returning nil
我正在尝试将一些 3D 触摸整合到应用程序中,但我 运行 遇到了一个奇怪的问题,其中 forceTouchCapability
检查在 viewDidLoad
上返回 nil
但不在 viewWillAppear/viewDidAppear
.
我知道这仅适用于 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];
}
}
在 LLDB 中,在 if
语句处有一个断点,输入 po [self.traitCollection forceTouchCapability]
returns 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 上安装这个
该视图尚未添加到视图层次结构中。您可以通过在调试控制台中检查超级视图来轻松看到这一点
(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 设置,您的视图将为 registered/unregistered。
我也看到了这个问题,发现检查设备是否支持强制触摸的最简单方法是通过屏幕实例进行。这是有道理的,因为该功能是屏幕的 属性。这样做意味着您不必担心 viewcontroller 或视图的生命周期。
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
}
正如@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)
}
}
}
}
我正在尝试将一些 3D 触摸整合到应用程序中,但我 运行 遇到了一个奇怪的问题,其中 forceTouchCapability
检查在 viewDidLoad
上返回 nil
但不在 viewWillAppear/viewDidAppear
.
我知道这仅适用于 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];
}
}
在 LLDB 中,在 if
语句处有一个断点,输入 po [self.traitCollection forceTouchCapability]
returns 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 上安装这个该视图尚未添加到视图层次结构中。您可以通过在调试控制台中检查超级视图来轻松看到这一点
(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 设置,您的视图将为 registered/unregistered。
我也看到了这个问题,发现检查设备是否支持强制触摸的最简单方法是通过屏幕实例进行。这是有道理的,因为该功能是屏幕的 属性。这样做意味着您不必担心 viewcontroller 或视图的生命周期。
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
}
正如@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)
}
}
}
}