上記のコメントを繰り返すことから始めます。
Swift のグローバル変数の概念を誤解している可能性があります。
グローバル変数がある場合、変数はグローバル スコープで定義されている (どこからでもアクセスできる) ため、ビュー/メソッド/クラスなどの間でそれを「渡す」必要はありません。
一般に、グローバル変数は良い考えではなく、避けたいものです。
グローバル変数とスウィフトの問題に関しては、シングルトンを議論に含めるべきです。たとえば、次の既存の SO スレッドを参照してください。
セグエによる TableViewController と ViewController 間の通信 (セグエの準備と巻き戻し)
(この回答は、現在のテーブルビュー/ビューコントローラープログラムの状態がどのように見えるかを詳しく知らなかったため、最終的には非常に、おそらく少し徹底しすぎました。長い回答と、それが読者にもたらす可能性のある不便について申し訳ありません)。
ここで、グローバル変数を残して、この例で 2 つのコントローラー間の通信に実行可能なオプションの 1 つ (とりわけ) について説明します。あなたの質問から、あなたの例を次のように要約します
- VC1 : ストーリーボード エントリ ポイント、 で
UITableViewController
構成されるUITableViewCell
。これらのセルでは、たとえば のインスタンスを介してテキストを表示しますUILabel
。
- VC2 :インスタンス
UIViewController
を含む、VC1 のセルからアクセスできるUITextField
ユーザーがこのテキスト フィールドにテキストを入力すると、そのテキストが VC2 の関連付けられたセル (VC2 へのアクセスに使用されたのは VC1 のセルであるという意味で関連付けられている) に表示されます。
VC1 と VC2 を (ココア タッチ) クラスTableViewController
( TableViewController.swift ) とViewController
( ViewController.swift ) にそれぞれ関連付けます。Table View Controller のセルは (cocoa touch) クラスTableViewCell
( TableViewCell.swift ) に関連付けられます。これらのクラスの詳細は以下のとおりです。
この単純な例では、VC1 をナビゲーション コントローラーに埋め込まないことに注意してください (それ以外の場合は、テーブル ビュー -> ビュー ナビゲーションに適しています)。
Table View Controller
ストーリーボードから開始し、およびのオブジェクトを追加します (オブジェクト ライブラリからドラッグ アンド ドロップ) View Controller
。また、テーブル ビュー コンテナには、自動的Table View
にTableViewCell
. ストーリーボードの続き:
- のコンテナに
UILabel
オブジェクトを追加します(必要に応じて配置します)TableViewCell
Table View Controller
- で、オブジェクトとオブジェクトを
View Controller
追加します(必要に応じて位置合わせします)。Text Field
Button
- エントリ ポイントを に設定し
Table View Controller
ます。
- その後、「Show」セグエを から に Ctrl キーを押しながらドラッグし
TableViewCell
ますView Controller
。
- セグエを選択
Show
し、属性インスペクタからその識別子、たとえばShowDetailを入力します。
- 最後に
TableViewCell
、(上記のように、属性インスペクターから) を選択して、セルの識別子を入力します。ここでは、単に識別子TableViewCellを使用します。
今のところストーリーボードは残し、Table View Controller
、 、View Controller
および前者のに関連付けられた 3 つのクラスを実装しTableViewCell
ます。
から始めて、サブクラスTable View Controller
を実装します。UITableViewController
ここでは、各セルNSMutableArray
のテキストを保持するためにan を使用する代わりに、単純に配列を使用することに注意してください。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?
}
コメントアウトされた 2 つのメソッドは、テーブル内UITableViewController
のセクション数 (例return 1
) とセル数 (例 ) でそれぞれ使用される標準的な方法です。return (numberOfCells ?? 0)
これらの修正はお任せします。
ここTableViewCell
で、テーブル ビュー内のオブジェクトをサブクラスのインスタンスに関連付けますUITableViewCell
。ここでは、セルに非常に単純なクラスを使用します。UILabel
単一のインスタンスを含む各セル(ストーリーボードの Ctrl キーを押しながらテーブル ビューのセル@IBOutlet
からドラッグして作成)。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
。例えば:
// 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 間の通信のコンテナーとして機能する文字列プロパティ ( ) も宣言しています。
ストーリーボードに戻り、---アイデンティティ インスペクタから--- 3 つのストーリーボード オブジェクト ( Table View Controller
、View Controller
、TableViewCell
) を、上で記述した関連クラスに関連付けます。
これでほぼ目標に到達しました。あとは、2 つのコントローラー間の通信方法を指定するだけです。
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 配列で指定されているように) 持ち込むことができますuserTextLabels
。ViewController.swiftのviewDidLoad(...)
メソッドを見て、この値が VC1 からどのように渡され、VC2 でデフォルト テキストとして設定されるかを確認します。UITextField
ここで、あなたが求めていた特定の通信方向である通信 VC2->VC1 のために、別のメソッドを (プログラムで) 再び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
と、セグエのソースであったビュー コントローラーのプロパティ、つまり、この場合は のインスタンスを取得するアンワインド アクションを定義しますViewController
。しかし、このアクションをトリガーするにはどうすればよいでしょうか。
絵コンテと に戻りView Controller
ます。オブジェクトの上部にある 3 つの小さなアイコンに注意してください。View Controller
具体的には、これらの最も右にあるExit
. Button
Ctrl キーを押しながらアクションをExit
アイコンにドラッグし、unwindToTableView
アクション セグエを選択します。ビューコントローラーのボタンをクリックすると、ビューが巻き戻され (終了し)、 のunwindToTableView
メソッドに着陸しTableViewController
ます。
結果のアプリは次のようになります。
これは私が予想していたよりもずっと長くなりましたが、書き始めると... とにかく、上記の方法は、当然、グローバル変数を使用しませんが、将来 ( prepareForSegue
) または履歴 ( unwindToTableView
) ビューへの参照を使用して (通常は現在または過去のビュー) または設定 (通常は現在または将来のビュー) の値を、これらの参照 (将来/履歴ビューへ) を使用して設定します。
Apple には、tableviewcontroller/viewcontroller コンテキストのサンプル アプリに関する非常に詳細なチュートリアルがあり、参照することをお勧めします。Swift のコーディングを始めたとき、私自身が非常に価値があると感じました。
iOS アプリの開発を開始する (Swift)