我正在将一些代码转换为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错误为“找不到'!''的重载接受提供的参数。“
如何正确测试标签是否存在?
感谢。
答案 0 :(得分:2)
有几点想法:
问题的标题是如何在Swift中使用谓词。坦率地说,我会考虑使用filter
方法,它完全取消了NSPredicate
:
let labels = subViews.filter { $0 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 { ... }
显然,如果你需要一系列标签用于其他目的,那么一定要构建它。但是,仅仅为了检查某些东西的存在而构建一个数组效率很低。
答案 1 :(得分:2)
正如您在原始问题中所写,您在Swift中提交了语法错误。条件条款不在括号内。
正如我们的评论所写,Swift抱怨是因为它无法将UILabel与nil与!=
运算符进行比较。
在过滤数组后使用as! [UILabel]
时,保证Swift labels
数组包含UILabel。然后在下一行中,您将labels[0]
分配给label
。通过询问索引0处的成员,你保证Swift确实会有一个成员在索引0。所以最后,当你试图检查label
是否为零时,Swift说"它不能是的,因为你告诉过我。"它知道label
不能为零,并且拒绝比较。
有很多方法可以改善这一点,但最简单的方法是改变:
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
的范围之外,以便之后可用。在我们分配之前,斯威夫特不会让我们做任何事情,但那没关系。
接下来,我们检查labels
索引0中是否有标签。如果是,请将其分配给label
。如果没有,我们将创建一个新标签并进行设置。
在我们将UILabel分配给标签后,您可以按计划继续自由继续。
我强烈建议您阅读Optionals和Optional Chaining,因为它们是Swift的核心,并且会对您的代码结构产生巨大影响。