我有两个ViewControllers。一个有一个TableView和一个Add Button,它将我们带到第二个ViewController,它有一个文本字段和一个动作按钮。用户应该在具有文本字段的第二个屏幕上的tableview中插入文本。
我为两个视图控制器制作了单独的swift文件。对于第二个视图,我正在导入我的第一个视图的类。但是,当我尝试点击添加按钮去第二个视图控制器时,我得到一个可选的包装错误。这是我得到的错误:致命错误: unexpectedly found nil while unwrapping an Optional value 。在调试模式下,它突出显示以下代码行:
tableview.setEditing(true, animated: true)
我的第一个具有tableview的视图控制器的代码:
class MainScreen : UIViewController, UITableViewDataSource, UITableViewDelegate {
var items = ["Apple", "Fish", "Dates", "Cereal", "Ice cream", "Lamb", "Potatoes", "Chicken", "Bread"]
@IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableview.setEditing(true, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let iD = "normal"
let cell = tableView.dequeueReusableCellWithIdentifier(iD, forIndexPath: indexPath)
cell.textLabel?.text = items[indexPath.row]
return cell
}
func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.None
}
func tableView(tableView: UITableView, moveRowAtIndexPath sourceIndexPath: NSIndexPath, toIndexPath destinationIndexPath: NSIndexPath) {
if (sourceIndexPath.row != destinationIndexPath.row){
let temp = items[sourceIndexPath.row]
items.removeAtIndex(sourceIndexPath.row)
items.insert(temp, atIndex: destinationIndexPath.row)
}
tableView.reloadData()
}
}
我的第二个视图控制器的代码,它包含textfield和一个用于将文本插入到我的数组中的按钮(项目)
class TextScreen : MainScreen {
@IBOutlet weak var keyboard: UITextField!
@IBAction func insert(sender: AnyObject) {
items.append(keyboard.text!)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
我不知道自己做错了什么。我还附上了截图。
答案 0 :(得分:0)
您尝试实现的目标应使用委托方法处理,而不是将MainScreen
子类化。
协议规定了类的结构。如果在协议中定义了函数。实现协议的类应该具有该功能。这就是为什么如果你引用来自MainScreen的委托就像delegate = self那样,持有委托的类可以触发协议中规定的任何函数。这会将函数中的数据从TextScreen传递到MainScreen中实现的函数
您想要将字符串附加到数组,您需要一个发送字符串(或处理它)的函数。礼仪也包括发件人。
创建协议:
protocol TextScreenDelegate {
func sendTextToDelegate(sender: TextScreen, text: String)
}
现在,您应该将一个委托放在TextScreen视图中作为该类的属性:
此委托将在想要使用数据的类和保存数据的类之间创建链接。当执行TextScreen中的协议的方法(delegate.sendTextToDelegate())时,它将转向引用它的任何视图,例如prepareforSegue中的MainScreen(参见下文)
var delegate : TextScreenDelegate?
现在让MainScreen符合您新创建的协议,如下所示:
现在我们需要确保MainScreen符合此协议。就像你使用UITableView等一样,你需要添加自己的协议。请记住,如果您不使用协议实现,TableView将无法使用我们的TextScreen!
class MainScreen : UIViewController, UITableViewDataSource, UITableViewDelegate, TextScreenDelegate
它会说它不符合,因为您缺少上面创建的委托方法。实施此操作并执行您想要执行的操作:
现在您已将协议添加到MainScreen,您应该创建自己在协议中定义的功能。其中的每个功能都需要添加到您的MainScreen中,如下所示:
func sendTextToDelegate(sender : TextScreen, text : String) {
self.items.append(text)
}
为了能够让TextView知道您想要将数据传播到该委托,您需要引用它。让你的prepareForSegue
看起来像这样:
这是我们在创建TextScreen和MainScreen之间的链接时所讨论的内容。 MainScreen(实现协议TextScreenDelegate)用于链接(请参阅vc.delegate = self)
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "YourIdentifier" {
if let vc = segue.destinationViewController as? TextScreen {
vc.delegate = self
}
}
}
剩下的就是现在调用TextScreen中的函数!当你执行你的行动时,让代表知道!
现在,在TextScreen中,您只需调用委托方法即可。使用您的代码:
@IBAction func insert(sender: AnyObject) {
// Always check if exists!
guard let text = self.keyboard.text
else {
print("error - no text in keyboard")
return
}
delegate?.sendTextToDelegate(sender: self, text: text)
}
确保TextScreen再次是UIView而不是MainScreen的子类:
TextScreen : UIView
这是一个独立的观点;)
这似乎是一种更清洁的方法来处理你想做的事情。
- 编辑2 -
测试委托方法有一种肮脏的方法。在AppDelegate中创建一个数组并附加到该数组。
在AppDelegate.swift
中var items : [String] = ["Apple", "Fish", "Dates", "Cereal", "Ice cream", "Lamb", "Potatoes", "Chicken", "Bread"]
现在在你的MainScreen.swift
中将您的商品更改为:
var items : [String] = []
并在你的viewDidLoad()
中let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
self.items = appDelegate.items
self.tableView.reloadData()
并在你TextScreen.swift
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.items.append('your item')
这会将它们保存在AppDelegate的数组中。但是,这仅建议用于tableView的测试目的。正确的方法是使用核心数据。其中有很多关于谷歌的例子。