質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.37%

規模の大きいプロジェクトでのコードによる画面遷移の設計

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,733

score 76

画面遷移の方法には通常navigationControllerによる遷移があるかと思われます。

あるプログラムを複数のモジュールに分割していて、異なるモジュール間でいかのように複数のViewControllerが存在します。
ModuleA: ViewController1
ModuleB: ViewController2, ViewController3
ModuleC: ViewController4
このとき、各ViewControllerのインスタンスを保持したまま、navigationControllerで遷移するために、プログラムをモジュール化する前までは、
AppDelegate.swift

let app = UIApplication.sharedApplication().delegate! as! AppDelegate

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?
  var navigationController: UINavigationController!
  var someViewController = SomeViewController()
  var otherViewController = OtherViewController()
  var anotherViewController = AnotherViewController()
  ...
}
と、インスタンスをすべてAppDelegateに配置する方法をとっていました。しかしモジュール化したことによって、それぞれのモジュールからAppDelegateのインスタンスを確保しようとすればimportで循環参照が発生してしまいます。

こういった場合、全てのViewControllerに対して
SomeViewController.swift in module1

public class SomeViewController : UIViewController {
  public weak var delegate: SomeViewControllerDelegate?
  
  func aTransitionMethod() {
    delegate?.pushViewControllerWithIdentifier("SomeViewController")
  }
}

public protocol SomeViewControllerDelegate: class {
  func pushViewControllerWithIdentifier(identifier: String)
  func popViewController()
}
といったように遷移用のdelegateを付加し、各モジュールがAppDelegateを含むモジュールを参照しないようにする方法を考えましたが、あまり良い方法に思えません。
あるいは、AppDelegateを使うことが問題なだけであって、すべての親のViewControllerを用意して、他のViewControllerのdelegateを一括で持つのが良いということでしょうか。

またこのやり方であれば、これらのViewControllerを全て参照するクラス(AppDelegateなど)で、identifierの値が実際にどのクラスを示すかswitchで分岐する必要が生じると思いますが、それは問題のない設計でしょうか。

より良い解決策はあるでしょうか。ご教示をお願いします。

追記
そもそもモジュールの分割方法として、ViewControllerがアチラコチラに散らばる設計が間違っているのでしょうか。そうであればモジュールは
Module1 = Modelのみ
Module2 = ViewControllerのみ
Module3 = カスタムViewのみ
などとして分割されるべきでしょうか。自分は元々は以下のように分離しています。
Module1 = Modelのみ
Module2 = ViewController & カスタムView の一部
Module3 = ViewController & カスタムView の一部
....

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

画面遷移のために、navigationControllerを参照したいだけなら、UIViewControllerのnavigationControllerプロパティで参照できます。

あと、Moduleを分けるなら、それぞれのModule同士の結合度が弱くなるように設計してください。
逆にいうと、結合度の強いものはModuleとして分割できません。

ちなみに、手動でビルドスクリプトを書けば、Module同士が相互参照していてもビルドできます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/08/24 12:38

    回答有難うございます。プロパティから参照できたのですね。
    差し支えなければですが、ビルドスクリプトの例を簡単に教えてはいただけないでしょうか。

    キャンセル

  • 2015/08/24 21:05

    SRCDIR=$SRCROOT/$TARGET_NAME
    SWIFT_FILES="*.swift"
    SRCFILES=`ls $SRCDIR/$SWIFT_FILES`
    MODULEDIR=$TARGET_BUILD_DIR/$PRODUCT_MODULE_NAME.swiftmodule

    mkdir -p $MODULEDIR
    swiftc -emit-module -module-name $PRODUCT_MODULE_NAME -module-link-name $PRODUCT_MODULE_NAME $SWIFT_OPTIMIZATION_LEVEL -sdk $SDKROOT $SRCFILES -I $TARGET_BUILD_DIR -F $TARGET_BUILD_DIR -L $TARGET_BUILD_DIR -g -o $MODULEDIR/$ARCHS.swiftmodule

    mkdir -p $OBJECT_FILE_DIR
    cd $OBJECT_FILE_DIR
    swiftc -emit-library -emit-object -module-name $PRODUCT_MODULE_NAME $SWIFT_OPTIMIZATION_LEVEL -sdk $SDKROOT -I $TARGET_BUILD_DIR -F $TARGET_BUILD_DIR -L $TARGET_BUILD_DIR -g $SRCFILES

    OBJECT_FILES="*.o"
    OBJFILES=`ls $OBJECT_FILE_DIR/$OBJECT_FILES`

    libtool -static -o $TARGET_BUILD_DIR/lib$PRODUCT_MODULE_NAME.a $OBJFILES

    swiftmoduleファイルはC言語のヘッダーファイル相当です。
    最初に相互参照している全てのModuleのswiftmoduleファイルを生成した後に、個々のModuleをコンパイルすれば、相互参照を解決できます。

    キャンセル

  • 2015/08/24 22:24

    返信有難うございます!ビルドスクリプトもとても役立ちそうです。
    swiftmoduleがそのような役割を持っていることを知りませんでした。ありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る