Swift泛型函数不起作用

时间:2014-12-26 07:57:07

标签: swift ios8 xcode6

所以,我在一个结构中创建了一个泛型函数,它有一些静态方法来帮助创建自定义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 = ...)甚至不是首先编译的。

真的不明白这一点。感谢任何帮助! :

1 个答案:

答案 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