私はiOSが初めてです。 ViewController間でデータを渡す際に問題が発生しています。 3つのviewController(view_1、view_2、view_3)があります。
ここに私のセットアップ:-
「view_1」のViewController reference(id)を「view_3」に送信したい。だから私はinclude "view_3"
を「view_1」に設定し、「view_3」の変数に値を設定します(view_3 *v3=[[view_3 alloc] init ]; v3.reference=self;
)。コンソールには次のように表示されます:
ビューコントローラー:-; <ViewController:0x89e9540>
「view_1」ではなく「view_3」で、コンソールでは
ビューコントローラー(ヌル)
しかし、このデータを処理するために「view_2」を使用した場合。しかし、どのように?私はこの行動を知りたい、そしてこれを作成するための解決策はありますか?
助けてください。
セグエがトリガーされたときの「宛先コントローラーへのデータの受け渡し」は、メソッドprepareForSegue:sender:
をオーバーライドすることにより実現されます。
通常、ソースView ControllerではなくdataをデスティネーションView Controllerに渡します。 「データ」は、アプリケーションの「モデル」の特定の側面です。 「ユーザー」などのオブジェクト、または「ユーザー」を含む配列などです。
destination View Controllerは、notがsource View Controllerの知識を持っているものとします。つまり、宛先View Controllerは、ソースView Controllerのヘッダーをインポートする必要はありません。
一方、source view controller (may_は、destination view controllerの具体的なクラスまたはbaseクラスの知識を持っています宛先View Controller。したがって、宛先View Controllerのヘッダーをインポートします。
参照: セグエがトリガーされたときの宛先コントローラーの構成
送信元と送信先の間に何らかの「通信プロトコル」が必要な場合は、委任を使用して他のView Controllerと通信できます。これには、@ protocolの定義(たとえば、メソッドdoneButton
を持つ)と、宛先View Controllerで定義されたプロパティdelegate
が含まれます。プロトコルは、宛先View Controllerのspecificの場合、宛先View Controllerのヘッダーで定義する必要があります。通常、プロトコルは、ソースコントローラーの要件からではなく、宛先コントローラーの観点から定義します。
次に、ソースView Controllerはデリゲートを作成し(それ自体がすでにそうでない場合)、宛先View Controllerのdelegate
を設定します。宛先View Controllerはデリゲートメソッドをデリゲートに送信し、デリゲートがそれを処理します。
これで、VC_AからVC_Bに「データ」を渡すのは簡単です。 prepareForSegue:sender:
を使用するいくつかの例を読む必要があります。たとえば、destination View Controllerには、表示するthingを表すプロパティdata
があります。ソースView Controllerは、prepareForSegue:sender:
でこのプロパティを設定する必要があります。
VC_AからVC_B経由でVC_Cにデータを渡すことも簡単です。
注:各View Controllerは、nextに適したdata
にするために、tailor(分離、変更、準備、スライス、変換など)itsdata
を実行できます。ビューコントローラー。
ソースビューコントローラVC_Bで使用できないデータがVC_Cに必要な場合、これを解決する方法がいくつかあります。ただし、これは通常bad designのサインです。
couldには、globalというアプリケーションモデルがあります。 「アプリケーションモデル」がタイプDocument
のオブジェクトであるとします。いつでも、そのアプリケーションモデルのインスタンスはoneだけであるとします。次に、モデルは「シングルトン」であり、次のようにアプリ内のどこからでもcouldにアクセスできます。
Document* document = [Document sharedDocument];
ただし、モデルのインスタンスを取得するための好ましい方法は、first View Controllerでのアクセスです。この場合、VC_Aにアクセスする必要があります。
次に、VC_AはDocument
インスタンスを次のビューコントローラーVC_Bに渡します。また、VC_BはドキュメントオブジェクトをVC_Cに渡します。
公式ドキュメント「 View Controller Programming Guide for iOS 」をお読みください。
「ユーザー」リストがあるとします。リストはTable View Controllerに表示される必要があり、1人のユーザーの詳細を示す詳細ビューも必要です。
Table View Controllerには、「data」プロパティusers
があります。
UsersTableViewController.h:
@interface UsersTableViewController : UIViewController
@property (nonatomic, readonly) NSArray* users;
@end
(厳密には、このuser
プロパティはパブリックである必要はありません。たとえば、テーブルビューがユーザー自体のリストを内部で取得する場合、外部からアクセスする必要はありません。
「users」配列は、行で表示される表ビューのdataです。各行には、ユーザーの「概要」が表示されます。
ユーザーの詳細は、detail view controllerに表示される必要があります。 Detail View Controllerのデータは、User
タイプの単一ユーザーです。
ユーザーがテーブルビューで特定の行をタブで移動すると、詳細ビューコントローラーが表示されます。表示する前に、Table View ControllerはDetail View Controllerを設定する必要があります。TableView Controllerは、Detail View Controllerの「データプロパティ」に現在選択されているserを割り当てます。したがって、Detail View Controllerには、publicプロパティuser
が必要です。
@interface UserViewController : UIViewController
@property (nonatomic) User* user;
@end
Table View Controllerは、prepareForSegue:sender:
のdetail View Controllerを構成します。
InUsersTableViewController.m
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"ShowUserDetails"]) {
UserViewController* userViewController = [segue destinationViewController];
userViewController.user = [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}
2番目の例はより複雑で、コントローラー間の通信を確立する手段として「委任」を使用します。
注意:
これは完全な例ではありません。この例の目的は、「委任」の使用方法を示します。例に示すように、データタスクのフル機能の実装には、かなりの労力が必要です。このようなシナリオでは、「委任」がこれを達成するための最も好ましいアプローチ(IMHO)になります。
したいとしましょう
詳細ビュー内から。
これらの「データタスク」は、詳細ビューコントローラー自体によって実行されるものではなく、代わりにデリゲートがこれらのデータタスクを担当します。
これらのデータアクションは、デリゲートによって処理されます。
@protocol UserDataSourceDelegateProtocol <NSObject>
- (User*) viewControllerUser:(UserViewControllerBase*)viewController;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithUpdatedUser:(User*)user;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithDeletedUser:(User*)user;
- (void) viewController:(UserViewControllerBase*)viewController dismissWithCreatedUser:(User*)user;
@end
このプロトコルは、基本的なCRUDメソッド(作成、読み取り、更新、削除)を反映しています。
繰り返しますが、Detail View Controller 自体がこれらのデータメソッドを実行することは望ましくありませんが、代わりにUserDataSourceDelegateProtocol
を実装するインスタンスによって実行されます。 Detail View Controllerにはこのデリゲートのプロパティがあり、これらの「データタスク」をデリゲートに送信します。
いくつかの詳細ビューコントローラ、抽象クラスUserViewControllerBase
のすべてのサブクラスがあり、show、editおよびcreateタスクを処理します。ユーザーの削除は、テーブルビューと「ユーザーの表示」ビューコントローラーで実行できます。
ShowUserViewController
EditUserViewController
NewUserViewController
たとえば、EditUserViewController
は、ユーザーが[戻る]ボタンを押したとき、およびユーザーがユーザーオブジェクトを変更した場合にviewController:dismissWithUpdatedUser:
を送信します。現在、デリゲートは詳細ビューを閉じることを許可する場合と許可しない場合があります。たとえば、検証エラーがある場合は許可されない場合があります。
UserDataSourceDelegateProtocol
プロトコルmayは、ルートビューコントローラー、たとえばテーブルビューコントローラーに実装されます。ただし、データタスクの処理を唯一の責任とする別のクラスの方が適切な場合があります。以下のサンプルでは、Table View Controllerもこのデータハンドラになります。
UserDataSourceDelegateProtocol
は、追加のヘッダーで定義できます。
UsersTableViewController.m:
#import "UserDataSourceDelegateProtocol.h"
#import "ShowUserViewController.h"
@interface UsersTableViewController () <UserDataSourceDelegateProtocol>
@property (nonatomic, readonly) NSArray* users;
@end
// This delegate will be called when the detail view controller request
// the user object which shall be displayed.
- (User*) viewControllerUser:(UserViewControllerBase*)viewController {
return [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
ここで、Table View ControllerはShow User Detail View Controllerを設定します:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:UserShowSegueID])
{
ShowUserViewController* showViewController = segue.destinationViewController;
showViewController.delegate = self; // Data Source Handler is self
}
}
「ユーザーの編集」ビューコントローラーは通常、「ユーザーの表示」ビューコントローラーの宛先ビューコントローラーであり、ユーザーが「編集」ボタンを押すと表示されます。
「ユーザーの表示」View Controllerは、「ユーザーの編集」View Controllerのデリゲートをセットアップし、同じデリゲートを取得します。
InShowUserViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:UserEditSegueID])
{
EditUserViewController* editViewController = segue.destinationViewController;
editViewController.delegate = self.delegate; // pass through the data source hanlder
}
}
データデリゲートは、更新されたユーザーを次のように処理できます。
UsersTableViewController.m:
- (void) viewController:(UserViewControllerBase*)viewController
dismissWithUpdatedUser:(User*)user {
if (/* is valid user and can be saved */) {
[viewController.presentingViewController dismissViewControllerAnimated:YES
completion:nil];
}
}
YouTubeのSwiftプロジェクト は、これを行う方法を最終的に理解するのに役立ちました。
同様の線に沿って簡単な例をセットアップしました。テキストフィールドにテキストを入力してボタンを押すと、次のView Controllerのラベルにテキストが配置されます。
それほど難しくありません。 Interface Builderでストーリーボードレイアウトを作成します。セグエを作るには control ボタンをクリックして、2番目のView Controllerにドラッグします。
最初のView Controllerのコードは
import UIKit
class FirstViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
// This function is called before the segue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// get a reference to the second view controller
let secondViewController = segue.destinationViewController as! SecondViewController
// set a variable in the second view controller with the String to pass
secondViewController.receivedString = textField.text!
}
}
そして、2番目のView Controllerのコードは
import UIKit
class SecondViewController: UIViewController {
@IBOutlet weak var label: UILabel!
// This variable will hold the data being passed from the First View Controller
var receivedString = ""
override func viewDidLoad() {
super.viewDidLoad()
// Used the text from the First View Controller to set the label
label.text = receivedString
}
}
UITextField
およびUILabel
のアウトレットを接続します。データをThird View Controllerに渡すプロセスは同じです。
解決策はありますが、最も適切な方法はありません。
ViewController3.h
-(void)getUser:(NSString *)strPassedUser;
viewController3.mに移動し、@ interfaceの上に次のような変数を追加します
NSString *recievingVariable ;
次に、ViewController3.m内のいくつか
-(void)getUser:(NSString *)strPassedUser
{
recievingVariable = strPassedUser;
}
ViewController1とViewController3をインポートすると、このようになります..
ViewController3 * vc3 = [ViewController3 alloc]getUser :@"me"];
この場合、関数getUser
が呼び出され、receivingVariable= me
。
より良い簡単なソリューション。
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"webView"];
webView = (WebViewController *)vc;
webView.strWebLink = @"http://www.Google.com/";
[self.navigationController showViewController:vc sender:self];
ソフトウェアエンジニアリングのシングルトンパターンは、クラスが1つのインスタンスのみを持ち、グローバルアクセスポイントを提供する設計パターンです。
一意のインスタンスがあるため、クラス変数とメソッドはアプリケーション/ネームスペース全体で共有されます。
例:
class Singleton {
static let sharedInstance = Singleton()
var studentId = 1281
}
そして、次のようにアプリのどこでも使用できます。
var studentId = Singleton.sharedInstance.studentId
print("Student Id: \(studentId)")
in Swift 4.0
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! SecondViewController
vc.username = self.username
}
確認してください
segue.destination
は、ここで本当の違いです。