在从 Obj-C 到 Swift 的转换中实现“如果对象不存在则执行此操作”
Implement 'Do this if object doesn't exist' in conversion from Obj-C to Swift
我正在将一些代码转换为 Swift,我遇到了一个似乎与解包可选相关的问题,因此我可以实现该模式:
如果对象存在,则使用它。如果不创建它。
我也想知道我对 NSPredicate 的使用。
这是有效的 Obj-C 代码:
UILabel *label = [[[cell.contentView subviews] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *subview, NSDictionary *bindings) {
return ([subview isKindOfClass:[UILabel class]]);
}]] firstObject];
if (!label) {
label = [[UILabel alloc] initWithFrame:cell.bounds];
label.font = [UIFont systemFontOfSize:10.f];
label.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
label.textAlignment = NSTextAlignmentCenter;
label.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:label];
}
这是我在 Swift 中修改后的代码:
let subViews = cell.contentView.subviews
let labelPredicate = NSPredicate { (UIView subview, _) -> Bool in
return subview.isKindOfClass(UILabel) }
let labels = (subViews as NSArray).filteredArrayUsingPredicate(labelPredicate) as! [UILabel]
let label = labels[0]
if (!label) {
label = UILabel(frame: view.bounds)
label.font = UIFont.systemFontOfSize( 10)
label.autoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth
label.textAlignment = NSTextAlignment.Center
label.backgroundColor = UIColor.clearColor()
cell.contentView.addSubview(label)
}
问题出现在 if(!label) 行,xcode 错误 "Could not find an overload for '!' that accepts the supplied arguments."
如何正确测试标签是否存在?
谢谢。
几个想法:
问题的标题是如何在Swift中使用谓词。坦率地说,我会考虑使用 filter
方法,它完全消除了 NSPredicate
:
let labels = subViews.filter { [=10=] is UILabel }
即使您想使用 NSPredicate
,我也可能会建议简化语法:
let labelPredicate = NSPredicate { (subview, _) -> Bool in subview is UILabel }
关于 if (!label)
语法,等效的 Swift 语法是
if label == nil { ... }
您不能在 Swift 中对任何随机类型使用 !
运算符。显式测试可选值是否为 nil
。
顺便说一下,构建标签数组以查看是否有标签的过程效率有点低。您可以在不使用 reduce
:
构建数组的情况下测试标签是否存在
let hasLabel = subViews.reduce(false) { alreadyFoundLabel, subview in alreadyFoundLabel || subview is UILabel }
if !hasLabel { ... }
或者,您可以在程序上循环遍历子视图:
var hasLabel = false
for control in subViews {
println(control)
if control is UILabel {
hasLabel = true
break;
}
}
if !hasLabel { ... }
显然,如果您出于其他目的需要标签数组,那么一定要构建它。但是仅仅为了检查某物是否存在而构建一个数组是低效的。
正如您在原始问题中所写,您在 Swift 中犯了一个语法错误。条件从句不放在括号中。
正如我们的评论中所写,Swift 正在抱怨,因为它无法使用 !=
运算符将 UILabel 与 nil 进行比较。
当您在过滤数组后使用 as! [UILabel]
时,您保证 Swift labels
数组将包含 UILabel。然后在下一行中,您将 labels[0]
分配给 label
。通过询问索引 0 处的成员,您保证 Swift 索引 0 处确实会有一个成员。所以最后,当您尝试检查 label
是否为 nil 时,Swift是说 "it cannot be, because you told me so." 它知道 label
不能为 nil,并且拒绝比较。
有很多方法可以改善这一点,但最简单的方法是更改:
let labels = // ...
let label = labels[0]
if label == nil {
// ...
}
至
let labels = // ...
let label: UILabel // Declare label, but do not assign in yet
if let lbl = labels.first {
label = lbl // Assign the UILabel in index 0
} else {
label = UILabel(frame: view.bounds) // Create a new UILabel
// ...
}
// Do whatever with label
在此示例中,我们声明 label
将是一个 UILabel,但尚未为其分配任何内容。我们将其声明在 if let / else
的范围之外,以便之后可用。 Swift 在我们分配给它之前不会让我们做任何事情,但没关系。
接下来我们检查labels
索引0中是否有标签。如果有,则将其分配给label
。如果没有,我们将创建一个新标签并进行设置。
在我们将 UILabel 分配给标签后,您可以按计划继续。
我强烈建议继续阅读 Optionals and Optional Chaining,因为它们是 Swift 的核心,并且对您构建代码的方式有很大影响。
我正在将一些代码转换为 Swift,我遇到了一个似乎与解包可选相关的问题,因此我可以实现该模式:
如果对象存在,则使用它。如果不创建它。
我也想知道我对 NSPredicate 的使用。
这是有效的 Obj-C 代码:
UILabel *label = [[[cell.contentView subviews] filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UIView *subview, NSDictionary *bindings) {
return ([subview isKindOfClass:[UILabel class]]);
}]] firstObject];
if (!label) {
label = [[UILabel alloc] initWithFrame:cell.bounds];
label.font = [UIFont systemFontOfSize:10.f];
label.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
label.textAlignment = NSTextAlignmentCenter;
label.backgroundColor = [UIColor clearColor];
[cell.contentView addSubview:label];
}
这是我在 Swift 中修改后的代码:
let subViews = cell.contentView.subviews
let labelPredicate = NSPredicate { (UIView subview, _) -> Bool in
return subview.isKindOfClass(UILabel) }
let labels = (subViews as NSArray).filteredArrayUsingPredicate(labelPredicate) as! [UILabel]
let label = labels[0]
if (!label) {
label = UILabel(frame: view.bounds)
label.font = UIFont.systemFontOfSize( 10)
label.autoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth
label.textAlignment = NSTextAlignment.Center
label.backgroundColor = UIColor.clearColor()
cell.contentView.addSubview(label)
}
问题出现在 if(!label) 行,xcode 错误 "Could not find an overload for '!' that accepts the supplied arguments."
如何正确测试标签是否存在?
谢谢。
几个想法:
问题的标题是如何在Swift中使用谓词。坦率地说,我会考虑使用
filter
方法,它完全消除了NSPredicate
:let labels = subViews.filter { [=10=] is UILabel }
即使您想使用
NSPredicate
,我也可能会建议简化语法:let labelPredicate = NSPredicate { (subview, _) -> Bool in subview is UILabel }
关于
if (!label)
语法,等效的 Swift 语法是if label == nil { ... }
您不能在 Swift 中对任何随机类型使用
!
运算符。显式测试可选值是否为nil
。顺便说一下,构建标签数组以查看是否有标签的过程效率有点低。您可以在不使用
构建数组的情况下测试标签是否存在reduce
:let hasLabel = subViews.reduce(false) { alreadyFoundLabel, subview in alreadyFoundLabel || subview is UILabel } if !hasLabel { ... }
或者,您可以在程序上循环遍历子视图:
var hasLabel = false for control in subViews { println(control) if control is UILabel { hasLabel = true break; } } if !hasLabel { ... }
显然,如果您出于其他目的需要标签数组,那么一定要构建它。但是仅仅为了检查某物是否存在而构建一个数组是低效的。
正如您在原始问题中所写,您在 Swift 中犯了一个语法错误。条件从句不放在括号中。
正如我们的评论中所写,Swift 正在抱怨,因为它无法使用 !=
运算符将 UILabel 与 nil 进行比较。
当您在过滤数组后使用 as! [UILabel]
时,您保证 Swift labels
数组将包含 UILabel。然后在下一行中,您将 labels[0]
分配给 label
。通过询问索引 0 处的成员,您保证 Swift 索引 0 处确实会有一个成员。所以最后,当您尝试检查 label
是否为 nil 时,Swift是说 "it cannot be, because you told me so." 它知道 label
不能为 nil,并且拒绝比较。
有很多方法可以改善这一点,但最简单的方法是更改:
let labels = // ...
let label = labels[0]
if label == nil {
// ...
}
至
let labels = // ...
let label: UILabel // Declare label, but do not assign in yet
if let lbl = labels.first {
label = lbl // Assign the UILabel in index 0
} else {
label = UILabel(frame: view.bounds) // Create a new UILabel
// ...
}
// Do whatever with label
在此示例中,我们声明 label
将是一个 UILabel,但尚未为其分配任何内容。我们将其声明在 if let / else
的范围之外,以便之后可用。 Swift 在我们分配给它之前不会让我们做任何事情,但没关系。
接下来我们检查labels
索引0中是否有标签。如果有,则将其分配给label
。如果没有,我们将创建一个新标签并进行设置。
在我们将 UILabel 分配给标签后,您可以按计划继续。
我强烈建议继续阅读 Optionals and Optional Chaining,因为它们是 Swift 的核心,并且对您构建代码的方式有很大影响。