在编写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的答案以获得详细说明。我只是想与大家分享这个。我不确定是否有人遇到过这个问题。
答案 0 :(得分:9)
以下是解释:
NSObject
的子类。setFoo:
因此, 属性TaskName
和taskName
的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
。这意味着UITextField
和UITextView
尚未初始化。这就是字段未初始化的原因。
您还问:为什么编译器没有显示任何错误?这是因为在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 的变量