所以,我在一个结构中创建了一个泛型函数,它有一些静态方法来帮助创建自定义UIButton
等等。所以我做了这段代码:
static func createAlertPicker<T: UIViewController where T: UIPickerViewDelegate, T: UIPickerViewDataSource>(#title: String, inout forPicker picker: UIPickerView, viewController: T) -> UIAlertController {
let alert = UIAlertController(title: title, message: "\n\n\n\n\n\n\n\n\n\n", preferredStyle: .Alert)
alert.view.tintColor = data.backgroundColor
picker = createPickerViewWithFrame(CGRectZero, delegate: viewController, dataSource: viewController, backgroundColor: UIColor.clearColor(), addToView: alert.view)
picker.frame = CGRect(x: 2, y: 70, width: 266, height: 162)
return alert
}
我这样做没有错误,但在ViewController中调用此方法时是这样的:
let alert = CreatorClass.createAlertPicker(title: "select sortage", forPicker: &self.pickerView!, viewController: self)
我收到一个疯狂的错误告诉我Type 'UIViewController' does not conform to protocol 'UIPickerViewDelegate'
。虽然它已实现,但这是ViewController的声明:
class PlayerDetails:UIViewController, UITableViewDataSource, UITableViewDelegate, UIPickerViewDelegate, UIPickerViewDataSource
顺便说一下,这个问题只出现在一个ViewController中,我多次调用它。也许应该提到这行代码(let alert = ...
)甚至不是首先编译的。
我真的不明白这一点。感谢任何帮助! :
答案 0 :(得分:3)
是的,错误完全是谎言。
问题在于中间参数:&self.pickerView!
。
self.pickerView
是可选的。您的选项包含一个引用,但展开该引用会将值的引用的新副本传回给您。您无法访问可选内部的原始引用。因此,当您调用!
时,您将获得一个不可变的值。您无法更改或分配,这意味着您无法将其作为inout
参数传递。
这是一个更简单的例子:
let i: Int? = 5
func f(inout i: Int) { i = 6 }
f(&i!) // error: 'Int' is not convertible to '@lvalue inout $T3’
这是编译器可以避免可能非常混乱的运行时错误 - 如果值传入并更改,它将对您实际想要更改的值没有任何影响。只有临时副本才会被更改。
它可能有点令人困惑,因为类是引用类型,所以你不习惯用价值术语来思考它们。但引用本身是值。你从解包中获得的是参考文献的副本,而不是所提到的东西的副本。
如果您将通话更改为以下内容,则应该有效:
if var picker = self.pickerView {
let alert = CreatorClass.createAlertPicker(title: "select sortage", forPicker: &picker, viewController: self)
// don’t forget to assign the value back...
self.pickerView = picker
}
如果您在强行打开它之前忘记将forPicker
设置为值,则此版本还具有不会在火焰中爆炸的好处。
但是,如果您使用的是inout
,那就是返回一个新的选择器(不会像您使用传入的值一样查看createAlertPicker
,只分配给它),那么为什么不要抛弃inout
并使函数返回一对值:
static func createAlertPicker
<T: UIViewController where T: UIPickerViewDelegate>
(#title: String, viewController: T)
// return a tuple
-> (UIPickerView,UIAlertController) {
// etc…
var picker = createPickerViewWithFrame(CGRectZero, delegate: viewController, dataSource: viewController, backgroundColor: UIColor.clearColor(), addToView: alert.view)
picker.frame = CGRect(x: 2, y: 70, width: 266, height: 162)
return (picker, alert)
}
let (picker, alert) = CreatorClass.createAlertPicker(title: "select sortage”, viewController: self)
self.pickerView = picker