Swift中的全局变量和可选绑定

时间:2015-12-13 02:04:32

标签: swift2 ios9 optional-variables

我对可选绑定,全局变量和放大器有一些非常简单的疑问。包装和展开。由于我是SWIFT的新手,因此了解乳房非常重要。他们的概念。

1)在Swift中,如果我声明一个全局变量,我有两个选项可以使它成为可选或非可选,所以让我有2-4个或更多的可选变量。因此,建议在

中绑定所有这些变量
viewDidLoad() method// so that I could use them without any problem of unwrapping and fatal error in my program.

2)让我通过下面的例子让自己更清楚 - 我的项目VC1&中有2个VC。 VC2。 VC2有一个文本字段,用户在其中输入一些值并在VC1的tabelview中显示它。

在Vc1中

var namevc1 = NSMutableArray?//holds the input of textfield to be passed from VC2. 

正如您所看到的,我的VC1是第一个在项目运行时加载的视图控制器,我使用一个可选变量来填充我的tabke vuew

'arr'

所以当应用程序第一次运行时它是空的。因此,在代码中使用其值时可能会导致致命错误。那么它的解决方案是什么呢?是否在

中取消绑定
viewDidLoad() 

方法或全部声明一个空的NSMutable数组类型来代替可选类型。

提前致谢。

1 个答案:

答案 0 :(得分:6)

我首先重复上面的评论。

可能你在Swift中误解了全局变量的概念。

  1. 如果您有一个全局变量,那么您将无法通过"传递"它在任何视图/方法/类等之间,因为变量是在全局范围内定义的(可在任何地方访问)。

  2. 一般来说,全局变量不是一个好主意,而是你想要避免的事情。

  3. 关于全局变量和swift的问题,你真的应该在讨论中加入 singletons 。参见例如以下现有的SO线程:

    TableViewController和ViewController之间通过segues进行通信(准备和放松segues)

    (这个答案最终非常可能有点过于彻底,因为我没有详细了解您当前的tableview / viewcontroller程序状态。对于冗长的答案和任何不便,我们深表歉意。可能会带给读者

    现在,让我们留下全局变量,并讨论一个(以及其他)可行的选项,用于示例中两个控制器之间的通信。从您的问题,我将总结您的示例如下

    • VC1 :故事板入口点,UITableViewControllerUITableViewCell组成,其中,在这些单元格中,您显示一些文字,比如说,通过UILabel
    • 的实例
    • VC2 UIViewController,可从VC1的单元格访问,包含UITextField个实例。当用户在此文本字段中输入文本时,您希望文本显示在VC2中的关联单元中(在VC1中用于访问VC2的单元格中关联)。< / LI>

    我们将VC1和VC2与(可可触摸)类TableViewController TableViewController.swift )和ViewController ViewController.swift ),分别。表视图控制器中的单元格将与(cocoa touch)类TableViewCell TableViewCell.swift )相关联。这些课程的详细信息如下。

    对于这个简单的例子,请注意我们不会将VC1嵌入导航控制器(否则适用于表格视图 - &gt;视图导航)。

    我们将从故事板开始,为Table View ControllerView Controller添加对象(从对象库中拖放)。表格视图容器还会自动在其Table View中包含TableViewCell。继续在故事板中:

    • UILabel个对象添加到TableViewCell中的Table View Controller容器中(根据需要对齐)
    • View Controller中,添加Text Field对象和Button对象(根据需要对齐)。
    • 将切入点设置为Table View Controller
    • 此后按住Ctrl键拖动&#39;显示&#39;从TableViewCellView Controller
    • 选择Show segue,然后从“属性”检查器中输入标识符,例如 ShowDetail
    • 最后,选中TableViewCell(如上所述;从属性检查器中),输入单元格的标识符。在这里,我们只使用标识符 TableViewCell

    我们现在暂时离开故事板并实施三个类,与Table View ControllerView Controller和前者&#39;相关联。 TableViewCell

    我们从Table View Controller开始,并实现我们的UITableViewController子类。请注意,此处,我们不是使用NSMutableArray来保存每个单元格中UITextLabel的文本,而是使用String数组。

    // TableViewController.swift
    Import UIKit
    
    class TableViewController: UITableViewController {
    
        // Properties
        var userTextLabels = [String]()
        var numberOfCells: Int?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            numberOfCells = loadSampleTextLabels() // Load sample labels.
        }
    
        func loadSampleTextLabels() -> Int {
            userTextLabels += ["Label #1", "Label #2", "Label #3"]
            return userTextLabels.count
        }
    
        // func numberOfSectionsInTableView(tableView: UITableView) ...
        // func tableView(tableView: UITableView, numberOfRowsInSection section: Int) ...
    
        override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cellIdentifier = ("TableViewCell")
            let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! TableViewCell
    
            // Text for current cell
            let cellText = userTextLabels[indexPath.row]
            cell.userSuppliedTextLabel.text = cellText
    
            return cell
        }
    
        // ... communication?
    }
    

    两个注释掉的方法是任何UITableViewController中使用的标准方法,分别是表格中的部分数量(例如return 1)和单元格(例如return (numberOfCells ?? 0))。我会把这些问题留给你。

    现在,我们将表视图中的TableViewCell个对象与子类的实例关联到UITableViewCell。在这里,我们将为我们的细胞使用一个非常简单的类;每个单元格只包含一个UILabel实例(通过故事板创建,从表格视图单元格中的@IBOutlet按住Ctrl键拖动UILabel

    // TableViewCell.swift
    import UIKit
    
    class TableViewCell: UITableViewCell {
    
        // Properties
        @IBOutlet weak var userSuppliedTextLabel: UILabel!
            // Ctrl-drag from UILabel (in TableViewCell) in storyboard
    
        override func awakeFromNib() {
            super.awakeFromNib()
        }
    
        override func setSelected(selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
        }
    
    }
    

    最后,对于从表格视图单元格访问的视图控制器:使用单个@IBOutlet到用于用户文本输入的UITextField,并使用前面的文本字段处理事件现有UITextFieldDelegate。 E.g:

    //  ViewController.swift
    import UIKit
    
    class ViewController: UIViewController, UITextFieldDelegate {
    
        // Properties
        @IBOutlet weak var userSuppliedText: UITextField!
            // Ctrl-drag from storyboard...
        var cellText: String?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            userSuppliedText.text = cellText ?? "..."
    
            // Handle the user input in the text field through delegate callbacks
            userSuppliedText.delegate = self
        }
    
        // UITextFieldDelegate
        func textFieldShouldReturn(textField: UITextField) -> Bool {
            // User finished typing (hit return): hide the keyboard.
            textField.resignFirstResponder()
            return true
        }
    
        func textFieldDidEndEditing(textField: UITextField) {
            cellText = textField.text
        }
    
    }
    

    我们在这里也声明了一个字符串属性(cellText),它将作为VC1和VC2之间通信的容器。

    我们返回故事板并从身份检查员---将三个故事板对象(Table View ControllerView ControllerTableViewCell)与我们关联的类关联起来# 39;我刚才写的。

    我们现在几乎达到了我们的目标;它只是指定如何在两个控制器之间进行通信。

    我们将从 VC1 VC2的通信开始。在上面的评论中,通过查看prepareForSegue(...)方法,您处于正确的轨道上(无论如何,针对此特定解决方案)。在Table View Controller的类中,我们添加以下方法:

    // ... add to TableViewController.swift
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    
        if segue.identifier == "ShowDetail" {
            let viewController = segue.destinationViewController as! ViewController
            if let selectedCell = sender as? TableViewCell {
                let indexPath = tableView.indexPathForCell(selectedCell)!
                let currentTextInCell = userTextLabels[indexPath.row]
                viewController.cellText = currentTextInCell // <-- note this
            }
        }
    }
    

    因此,对于VC1-> VC2通信,我们可以(在此示例中)带来当前在发送方单元中占用UILabel的任何现有文本(由String数组{{1}指定) })。查看 ViewController.swift 中的userTextLabels方法,了解如何从VC1传递此值,并将其设置为VC2中viewDidLoad(...)的默认文本。

    现在,对于通信VC2-&gt; VC1,这是您询问的具体通信方向,再次添加另一个方法(以编程方式)到 TableViewController.swift

    UITextField

    在这里,我们定义一个展开动作,当触发时,它会检索作为segue源的视图控制器的// ... add to TableViewController.swift @IBAction func unwindToTableView(sender: UIStoryboardSegue) { if let sourceViewController = sender.sourceViewController as? ViewController, text = sourceViewController.cellText { // ^ note 2nd clause of if let statement above if let selectedIndexPath = tableView.indexPathForSelectedRow { // Update cell text userTextLabels[selectedIndexPath.row] = text tableView.reloadRowsAtIndexPaths([selectedIndexPath], withRowAnimation: .None) } } } 属性,即在我们的例子中,cellText的实例。但是我们如何触发这一行动呢?

    返回故事板和ViewController。请注意View Controller对象顶部的三个小图标,更具体地说,最右边的三个小图标,名为View Controller。按住Ctrl键并拖动ExitButton图标的操作,然后选择Exit动作搜索。单击视图控制器按钮时,视图将展开(退出)并以unwindToTableView中的unwindToTableView方法着陆。

    生成的应用应该如下所示:

    enter image description here

    这比我预期的要长,但是一旦你开始写作......无论如何,上面的方法自然不使用全局变量,而是使用对未来(TableViewController)或历史的引用(prepareForSegue)通过使用这些引用(到未来/历史视图)来获取(通常来自当前或历史视图)或设置(通常在当前未来视图中)值。

    Apple在tableviewcontroller / viewcontroller上下文中有一个关于示例应用程序的非常全面的教程,我建议将其用完。当我开始编写Swift编码时,我发现它非常有价值。

    Start Developing iOS Apps (Swift)