2015-11-19 22 views
8

再利用可能なビューコントローラUsersViewControllerBaseを作成したいと思います。SwiftでカスタムUIViewControllerをサブクラス化する方法は?

UsersViewControllerBaseUIViewControllerを拡張し、2つのデリゲート(UITableViewDelegateUITableViewDataSource)を実装し、2つのビュー(UITableViewUISegmentedControl)を有する

目標はUsersViewControllerBaseの実装を継承とにセグメント化された制御のセグメント化されたアイテムをカスタマイズすることですUsersViewControllerクラス。

class UsersViewControllerBase: UIViewController, UITableViewDelegate, UITableViewDataSource{ 
    @IBOutlet weak var segmentedControl: UISegmentedControl! 
    @IBOutlet weak var tableView: UITableView! 
    //implementation of delegates 
} 

class UsersViewController: UsersViewControllerBase { 
} 

UsersViewControllerBaseは、識別子が指定され、ストーリーボードに存在し、すべてのコンセントが接続されています。

は疑問がUsersViewControllerBaseすべてが

let usersViewControllerBase = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("UsersViewControllerBase") as? UsersViewControllerBase 

を作品の私は、インスタンスを作成するときに、私はすべてのビューを継承するUsersViewControllerとUsersViewControllerBase

の機能を初期化する方法である。しかし、私はUsersViewControllerのインスタンスを作成するときにnilアウトレット (私は単純なUIViewControllerを作成し、それにストーリーボードのUsersViewControllerクラスを割り当てました)

let usersViewController = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("UsersViewController") as? UsersViewController 

ビューは継承されていないようです。

私はストーリーボードからの景色や店舗を持つコントローラを取得しUsersViewControllerBaseでinitメソッド期待:

class UsersViewControllerBase: UIViewController, UITableViewDelegate, UITableViewDataSource{ 
     @IBOutlet weak var segmentedControl: UISegmentedControl! 
     @IBOutlet weak var tableView: UITableView! 
     init(){ 
     let usersViewControllerBase = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("UsersViewControllerBase") as? UsersViewControllerBase 
     self = usersViewControllerBase //but that doesn't compile 
     } 
    } 

をそして私はUsersViewControllerを初期化します:

動作しない
let usersViewController = UsersViewController() 

しかし、残念なことに

+0

さて、彼らは継承されているので、何かが間違っています(ストーリーボードシーンの設定など)。あなたはそれらのアウトレットを_connect_することを覚えましたか? – matt

+0

いいえ私は、UsersViewControllerBaseで既に接続されている(おそらく継承されている)と考えて、私はアウトレットをUsersViewControllerに接続しませんでした。そしてそのアイデアは、UsersViewControllerの同じビューを再作成するのではなく、UsersViewControllerBaseから継承します。 – Alex

答えて

3

、プロセスは、本質的に:

  • その識別子にシーンを見つけました。
  • このシーンの基本クラスを決定します。
  • このクラスのインスタンスを返します。

そして、あなたが最初にviewにアクセスするとき、それは以下となります。そのストーリーボードのシーンで概説したよう

  • は、ビュー階層を作成します。
  • はアウトレットに接続します。

(プロセスが実際よりも複雑ですが、私はこのワークフローの重要な要素にそれを軽減しようとしている。)

このワークフローの意味合いがコンセントやベースクラスということですinstantiateViewControllerWithIdentifierに渡す固有のストーリーボードIDによって決まります。したがって、基本クラスのすべてのサブクラスに対して、別個のストーリーボードシーンが必要であり、その特定のサブクラスにコンセントを接続しています。

リクエストした内容を達成する方法があります。ビューコントローラのストーリーボードシーンを使用する代わりに、ビューコントローラにloadViewviewDidLoadと混同しないでください)を実装し、ビューコントローラクラスに必要なビュー階層をプログラムで作成させることができます。 Appleはこのプロセスの紹介をiOS向けの View Controller Programming Guideで行っていましたが、それ以降はこの議論を辞退しましたが、まだlegacy documentationにあります。

私は個人的には、非常に説得力のあるケースがない限り、プログラムで作成されたビューの古い世界に戻ることを強いられません。私は、View Controllerのサブクラスのアプローチを放棄し、単一のクラス(つまり私がストーリーボードの世界に戻ってきたことを意味する)を採用し、その特定のインスタンスから望む振る舞いを指示する識別子を渡す方が好きかもしれません。そのシーン。 これについていくつかのオブジェクト指向を維持したい場合は、このビューコントローラクラスで設定したいくつかのプロパティに基づいて、データソースのカスタムクラスをインスタンス化し、委譲することができます。

プログラマチックに作成されたビュー階層ではなく、本当に動的なビューコントローラの動作が必要な場合、私はこの道を踏み出す傾向があります。 さらに単純ではありませんが、オリジナルのView Controllerサブクラス化アプローチを採用し、各サブクラスのストーリーボードで別々のシーンが必要であることを受け入れるだけです。

+0

非常に良い説明、ありがとうございます。私は、 "サブクラス化アプローチ"を使い、各サブクラスごとにシーンを分離する方が好きです。少なくとも私はコードの重複を避け、ストーリーボードでの同じシーンのコピー貼り付けは大したことではありません。 – Alex

+0

VCをアウトレットでサブクラス化する機能がまだ必要な場合は、.xibアプローチをとることができます。 すべてのビューとアウトレットを持つ.xibを作成し、そのクラスを作成します。 'UserViewControllerBase'は、この.xibを' viewDidLoad() 'の' self.view'に追加し、カスタムビューをメンバとして持ちます。 'UsersViewController'は基本クラスを継承し、そのスーパークラスからのカスタムビューを持ち、メンバカスタムビューを通してすべてのアウトレットにアクセスします。 個人的には、私はこのソリューションが大好きではありませんが、ストーリーボードVCを複製するよりも優れています – gutte

0

問題は、ストーリーボードにシーンを作成したが、ビューコントローラーのビューにサブビューやコンどんなコンセントにも接続できないため、インターフェイスは空白です。

いくつかの異なるView Controllerクラスのインスタンスに関連して、ビューとサブビューのコレクションを再利用することを目標としている場合は、最も簡単な方法は、コードで作成したくない場合は、.xibファイルを開き、ビューコントローラ独自のビューロード処理後にコードにロードします(例:viewDidLoad)。

しかし、このビューコントローラの異なるインスタンスでセグメント化されたコントロールのセグメント化された項目をカスタマイズするだけの目的なら、最も簡単なアプローチは、1つのビューコントローラクラスと1つの対応するインターフェイスデザインを用意し、 。ただし、は、視覚的にデザインすることが重要な場合は、それぞれのセグメント化コントロールを独自の.xibからロードすることができます。もしinstantiateViewControllerWithIdentifier介してビューコントローラをインスタンス化すると、以下のよう

5

だから、あなたはあなたの基本クラスを持っている:

class UsersViewControllerBase: UIViewController, UITableViewDelegate, UITableViewDataSource { 
    @IBOutlet weak var segmentedControl: UISegmentedControl! 
    @IBOutlet weak var tableView: UITableView! 
    //implementation of delegates 
} 

そして、あなたのサブクラス:

class UsersViewController: UsersViewControllerBase { 
    var text = "Hello!" 
} 

適切にサブクラスを使用するには、(のようなもの)を行う必要があり、この:

class TestViewController: UIViewController { 
    ... 
    func doSomething() { 
     let storyboard = UIStoryboard(name: "Main", bundle: nil) 
     //Instantiate as base 
     let usersViewController = storyboard.instantiateViewControllerWithIdentifier("UsersViewControllerBase") as! UsersViewControllerBase 
     //Replace the class with the desired subclass 
     object_setClass(usersViewController, UsersViewController.self) 
     //But you also need to access the instance variable 'text', so: 
     let subclassObject = usersViewController as! UsersViewController 
     subclassObject.text = "Hello! World." 
     //Use UsersViewController object as desired. For example: 
     navigationController?.pushViewController(subclassObject, animated: true) 
    } 
} 
関連する問題