在lowerCamelCase中命名变量时的奇怪行为

时间:2014-07-17 12:23:18

标签: ios swift

在编写Master-Detail应用程序时,我在Swift中遇到了一个奇怪的行为。

以下是情景
这是一个简单的任务管理器应用程序。我在TaskDetailView上有两个文本控件( TaskName TaskDescription )和两个具有相同名称但在lowerCamelCase中的字符串变量( taskName taskDescription )在TaskDetailViewController中声明。

@IBOutlet var TaskName:UITextField!         //UpperCamelCase
@IBOutlet var TaskDescription:UITextView!   //UpperCamelCase
var taskName:String?                        //lowerCamelCase
var taskDescription:String?                 //lowerCamelCase

我像往常一样在ViewDidLoad()上设置Text控件的值:

override func viewDidLoad() {
    super.viewDidLoad()
    TaskName.text = taskName
    TaskDescription.text = taskDescription
}

我像往常一样在prepareForSegue(来自TaskListViewController)中传递数据:

override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
    if(segue.identifier == "TaskListSegue"){
        let detailViewController = segue.destinationViewController as ToDoTaskViewController
        let (task, desc) = m_ToDoListManager.GetTask(TaskListView.indexPathForSelectedRow().row)
        println("selected \(task) \(desc)")
        detailViewController.taskName = task
        detailViewController.taskDescription = desc
    }
}

实施一切的方式是正确的。 但是现在当您运行应用程序时,未设置文本控件的值。 实际上,也没有设置变量的值。

这里一定要发生什么?
我已经调查了这个问题,并提出了一个解决方案(请参阅下面的答案)。另请参阅Martin R的答案以获得详细说明。我只是想与大家分享这个。我不确定是否有人遇到过这个问题。

更新
这是实际代码:https://github.com/Abbyjeet/Swift-ToDoList

3 个答案:

答案 0 :(得分:9)

以下是解释:

  • 您的Swift类(最终)是NSObject的子类。
  • 因此,属性是具有getter和setter方法的Objective-C属性。
  • 属性的setter方法的名称由大写构建 财产名称的字母,例如属性“foo”具有setter方法setFoo:

因此, 属性TaskNametaskName的setter方法称为setTaskName:

在Objective-C文件中,您将收到编译器错误

  

合成属性'taskName'和'TaskName'都声称setter'setTaskName:' - 使用此setter会导致意外行为

但是Swift编译器没有发现冲突。

问题的一个小演示:

class MyClass : NSObject {
    var prop : String?
    var Prop : String?
}

let mc = MyClass()
mc.prop = "foo"
mc.Prop = "bar"
println(mc.prop) // bar
println(mc.Prop) // nil

在你的情况下

TaskName.text = ...

设置“taskName”属性,而不是“TaskName”。属性有不同的类型, 所以行为是未定义的。

请注意,“Objective-C兼容”属性只会出现 问题。如果删除了 在上面的例子中,NSObject超类,输出是预期的。

结论:您不能只有两个不同的Objective-C属性 第一个字母的情况。 Swift编译器应该在这里失败并出现错误(如 Objective-C编译器确实如此。

答案 1 :(得分:0)

您面临的问题与快速语言无关。在prepareForSegue之前调用方法loadView。这意味着UITextFieldUITextView尚未初始化。这就是字段未初始化的原因。

您还问:为什么编译器没有显示任何错误?这是因为在nil对象上执行的任何选择器都不会抛出异常。所以例如(抱歉obj-c):

UITextField *tf = nil;
[tf setText:@"NewText"];

不会显示任何错误。

正如您在解决问题的答案中所说,您需要向目标控制器添加其他字段(复制粘贴):

var tAskName:String?                        //cUstomCamelCase
var tAskDescription:String?                 //cUstomCamelCase

答案 2 :(得分:-2)

为什么会这样?
我相信内部Swift正在将lowerCamelCase用于尚未初始化的文本控件名称,因此无法设置值。但是我也没有遇到任何错误也很奇怪。

我是如何解决的?
我知道Swift区分大小写。所以这不是问题。所以我只更改了一个字母的大小写,并将变量命名为( tAskName tAskDescription ),并将值设置为预期值。

@IBOutlet var TaskName:UITextField!         //UpperCamelCase
@IBOutlet var TaskDescription:UITextView!   //UpperCamelCase
var tAskName:String?                        //cUstomCamelCase
var tAskDescription:String?                 //cUstomCamelCase

所以结论是如果我有一个名为 TaskName 的控件,我就不能有一个名为 taskName 的变量