Swift中的全局变量和可选绑定 [英] Global variable and optional binding in Swift
问题描述
我对可选绑定,全局变量&包装和开卷.由于我是SWIFT的新手,因此了解山雀和山雀非常重要.他们的概念.
I have some quite simple doubt regarding optional binding,global variable & wrapping and unwrapping . Since I am new to SWIFT, its very important to understand the tits & bits of their concepts.
1)在Swift中,如果我声明一个全局变量,我有2个选项可以将其设置为可选或非可选,因此让我拥有2-4个或更多可选变量.因此,建议将
1) In Swift if I declare a global variable, I have 2 options either to make it optional or non optional, so let I am having 2-4 or more optional variables . So is it advisable to optional bind all those variables in
viewDidLoad() method// so that I could use them without any problem of unwrapping and fatal error in my program.
2)通过下面的示例让我更加清楚-我的项目VC1& 2中有2个VC. VC2. VC2有一个文本字段,用户可以在其中输入一些值,并将其显示在VC1的tabelview中.
2) Let me make myself more clear by the following example- I have 2 VC in my project VC1 & VC2 . VC2 has a text field in which user enters some value and displays it in a tabelview in VC1.
在Vc1中
var namevc1 = NSMutableArray?//holds the input of textfield to be passed from VC2.
如您所见,我的VC1是第一个在我的项目运行时加载的视图控制器,我正在使用一个可选变量填充Tabke vuew,即
As you can see, my VC1 is the first view controller that loads when my project runs and I am using an optional variable to populate my tabke vuew that is
'arr'
因此,当应用程序首次运行时,它为empty.因此,在代码中使用其值时,可能会导致致命错误.那么,是否将其取消绑定在
So when the app runs for the first time its empty . So it might cause a fatal error while using its value in the code. So what is its solution whether to unbind it in the
viewDidLoad()
方法或总共声明一个空的NSMutable数组类型来代替可选类型.
method or in all total declare an empty NSMutable array type in place of optional type .
谢谢.
推荐答案
我将从上面重复我的评论开始.
I'll start by repeating the my comment from above.
可能您误解了Swift中的全局变量的概念.
Possibly you've misunderstanding the concept of global variables in Swift.
-
如果您具有全局变量,则无需在任何视图/方法/类等之间传递"它,因为该变量是在全局范围内定义的(可在任何地方访问).
If you have a global variable, you won't have to "pass" it between any views/methods/classes etc, because the variable is defined at global scope (accessible everywhere).
通常,全局变量不是一个好主意,而您要避免.
Generally global variables is not a good idea, and something that you want to avoid.
关于全局变量和快速问题,您确实应该在讨论中加入单例.参见例如以下现有的SO线程:
Regarding the matter of global variables and swift, you really should include singletons into the discussion. See e.g. the following existing SO thread(s):
TableseController和ViewController之间通过Segues(为& Unwind Segues做准备)之间的通信
(此答案最终可能非常彻底,因为我不详细了解您当前的tableview/viewcontroller程序状态如何.抱歉,冗长的答案以及可能给您带来的不便给读者看).
现在,让我们留下全局变量,并在您的示例中讨论两个控制器之间进行通信的一个可行的选择.从您的问题中,我将总结您的示例,如下所示:
Now, lets leave global variables and discuss one (among other) viable options for the communication between the two controllers in your example. From your question, I'll summarize your example as follows
- VC1 :情节提要入口点,一个由
UITableViewCell
组成的UITableViewController
,在这些单元格中,您可以通过以下方式显示一些文本,例如UILabel
. - VC2 :一个
UIViewController
,可从VC1的单元中访问,其中包含一个UITextField
实例.当用户在此文本字段中输入文本时,您希望将文本显示在VC2中的关联单元格中(在某种意义上,该关联是访问VC2的是VC1中的单元格.)/li>
- VC1: storyboard entry point, a
UITableViewController
consisting ofUITableViewCell
s, where, in these cells, you display some text, say, via instances ofUILabel
. - VC2: a
UIViewController
, accessible from the cells of VC1, containing anUITextField
instance. When user enters text into this text field, your want the text to be displayed in the associated cell in VC2 (associated in the sense that it was the cell in VC1 that was used to access VC2).
我们将VC1和VC2分别与(可可触摸)类TableViewController
( TableViewController.swift )和ViewController
( ViewController.swift )相关联.表格视图控制器中的单元格将与(可可触摸)类TableViewCell
( TableViewCell.swift )关联.这些课程的详细信息如下.
We'll associate VC1 and VC2 with (cocoa touch) classes TableViewController
(TableViewController.swift) and ViewController
(ViewController.swift), respectively. The cells in the table view controller will be associated with (cocoa touch) class TableViewCell
(TableViewCell.swift). Details for these classes follow below.
对于这个简单的示例,请注意,我们不会将VC1嵌入到导航控制器中(否则适用于表视图->视图导航).
For this simple example, note that we will not embed VC1 into a navigation controller (which is otherwise appropriate for table view -> view navigation).
我们将从情节提要开始,为Table View Controller
和View Controller
添加对象(从对象库中拖放).表格视图容器还将自动在其Table View
中包含一个TableViewCell
.在情节提要中继续:
We'll start in the storyboard, adding objects (drag-and-drop from object library) for a Table View Controller
and a View Controller
. The table view container will also, automatically, contain, in its Table View
, a TableViewCell
. Continuing in the storyboard:
- 将
UILabel
对象添加到Table View Controller
中的TableViewCell
容器中(根据需要对齐) - 在
View Controller
中,添加一个Text Field
对象和一个Button
对象(根据需要对齐它们). - 将入口点设置为
Table View Controller
. - 此后,按住Ctrl并将显示"序列从
TableViewCell
拖动到View Controller
. - 选择
Show
segue,然后从属性"检查器中为其输入一个标识符,例如 ShowDetail . - 最后,选择
TableViewCell
(如上所述;从属性检查器中),输入单元格的标识符.在这里,我们将仅使用标识符 TableViewCell .
- Add a
UILabel
object to theTableViewCell
container in theTable View Controller
(align it as you wish) - In the
View Controller
, add aText Field
object and aButton
object (align them as you wish). - Set the entry point to the
Table View Controller
. - Thereafter Ctrl-drag a 'Show' segue from the
TableViewCell
to theView Controller
. - Select the
Show
segue and, from the Attributes inspector, enter an identifier for it, say, ShowDetail. - Finally, with the
TableViewCell
selected, (as above; from the attribute inspector), enter an identifier for the cell. Here, we'll use simply use identifier TableViewCell.
我们现在暂时离开情节提要,并实现三个与Table View Controller
,View Controller
和前者的TableViewCell
相关的类.
We now leave the storyboard for now and implement three classes, associated with the Table View Controller
, the View Controller
and the formers' TableViewCell
.
我们从Table View Controller
开始,并实现我们的UITableViewController
子类.请注意,在这里,我们不使用NSMutableArray
来保存每个单元格中的UITextLabel
文本,而是简单地使用String
数组.
We start with the Table View Controller
, and implement our UITableViewController
sub-class. Note that here, instead of using an NSMutableArray
to hold the texts of the UITextLabel
in each cell, we'll simply use a String
array.
// 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)
).我将把这些修复给您.
Where the two commented out methods are standard methods used in any UITableViewController
, for number of sections (e.g. return 1
) and cells (e.g. return (numberOfCells ?? 0)
) in the table, respectively. I'll leave fixing these to you.
现在,我们将表视图中的TableViewCell
对象与子类的实例关联到UITableViewCell
.在这里,我们将为单元格使用一个非常简单的类.每个单元格仅包含一个UILabel
实例(通过情节提要板Ctrl-拖动从表视图单元格中的UILabel
作为@IBOutlet
创建).
Now, we associate the TableViewCell
object(s) in the table view with instances of a subclass to UITableViewCell
. Here, we'll use a very simple class for our cells; each cell just containing a single UILabel
instance (created via storyboard Ctrl-drag as an @IBOutlet
from the UILabel
in the table view cells).
// 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)
}
}
最后,对于从表视图单元格访问的视图控制器:对用于用户文本输入的UITextField
使用单个@IBOutlet
,并使用预先存在的UITextFieldDelegate
处理此文本字段中的事件.例如:
Finally, for the view controller that is accessed from the table view cells: use a single @IBOutlet
to the UITextField
used for user text input, and handle events in this text field using the pre-existing 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之间通信的容器.
We've also declared a string property (cellText
) here, that will as act as container for communication between VC1 and VC2.
我们返回情节提要,并-从身份检查器中--将三个情节提要对象(Table View Controller
,View Controller
,TableViewCell
)与我们上面刚刚编写的关联类相关联.
We return to the storyboard and---from the Identity inspector---associate the three storyboard objects (Table View Controller
, View Controller
, TableViewCell
) with their associated classes that we've just written above.
我们现在几乎要实现目标了;仅需指定两个控制器之间的通信方式.
We're now almost at our goal; it only remains to specify how to communicate between the two controllers.
我们将从VC1 到 VC2的通信开始.在上面的评论中,通过查看prepareForSegue(...)
方法,您处在正确的轨道上(无论如何对于此特定解决方案).在Table View Controller
的类中,我们添加以下方法:
We'll begin with communication from VC1 to VC2. In your comment above, you were on the right track (for this specific solution, anyway) by looking at the prepareForSegue(...)
method. In the class for the Table View Controller
, we add the following method:
// ... 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数组userTextLabels
指定).查看 ViewController.swift 中的viewDidLoad(...)
方法,以了解如何从VC1传递此值并在VC2的UITextField
中将其设置为默认文本.
Hence, for VC1->VC2 communication, we can (in this example) bring whatever existing text that is currently occupying the UILabel
in the sender cell (as is specified by the String array userTextLabels
). Look at the viewDidLoad(...)
method in the ViewController.swift to see how this value is passed from VC1 and set as default text in the UITextField
in VC2.
现在,对于您要询问的特定通信方向VC2-> VC1,再次(以编程方式)向 TableViewController.swift 添加另一种方法:
Now, for communication VC2->VC1, which was the specific communication direction you were asking about, add another method (programmatically), again to TableViewController.swift:
// ... 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
属性,该属性是segue的源,即在我们的情况下为ViewController
的实例.但是,我们如何触发此动作?
Here, we define an unwind action that, when triggered, retrieves the cellText
property of the view controller that was the source of the segue, i.e., in our case, the instance of ViewController
. But how do we trigger this action?
返回情节提要和View Controller
.请注意View Controller
对象顶部的三个小图标,更具体地说,是它们中最右边的三个名为Exit
的图标.按住Ctrl并将动作从Button
拖动到Exit
图标,然后选择unwindToTableView
动作选择.当您单击视图控制器的按钮时,视图将展开(退出)并降落到TableViewController
中的unwindToTableView
方法.
Return to the storyboard and the View Controller
. Note the three little icons in the top of the View Controller
object, more specifically, the right-most of these, named Exit
. Ctrl-drag an action from your Button
to the Exit
icon, and select the unwindToTableView
Action Segue. When you click your button the view controller, the view unwind (exit) and land at the unwindToTableView
method in the TableViewController
.
生成的应用程序应如下所示:
The resulting app should look something like this:
这比我预期的要长,但是一旦您开始编写...无论如何,以上方法自然不使用全局变量,而是使用对future(prepareForSegue
)或历史(prepareForSegue
c59>)通过使用这些引用(到未来/历史视图)来获取(通常从当前或历史视图获取)或设置(通常从当前的未来视图获取)值.
This was way longer than I had expected, but once you get started writing... Anyway, the method above uses, naturally, no global variables, but make use of references to future (prepareForSegue
) or historic (unwindToTableView
) views to get (generally from current or historic view) or set (generally in current of future view) values by using these references (to future/historic view).
Apple在tableviewcontroller/viewcontroller上下文中的示例应用程序上有自己的非常详尽的教程,我建议复习一下.当我开始编写Swift时,我发现它非常有价值.
Apple has their own very thorough tutorial on an example app in the tableviewcontroller/viewcontroller context that I would recommend going over. I found it very valuable myself when I started coding Swift.
这篇关于Swift中的全局变量和可选绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!