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

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

ただいまの
回答率

87.95%

storyboardのインスタンスを比較したい

解決済

回答 3

投稿 編集

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

score 13

前提・実現したいこと

swiftでのstoryboardインスタンスの比較演算子===について思っていることと挙動が違うので教えて下さい。
該当のソースコードをデバッグすると、同じアドレスを参照してるのに
ifの結果はelseに飛んでしまいます。
どのようにしたら2つのstoryboardを比較できるのでしょうか?

一意で有効なプロパティがあればそちらでも比較してみたいです。
(実際にはないですが、storyboard.nameとかstoryboard.IDのようなものがあれば)

よろしくお願いいたします。

発生している問題・エラーメッセージ

エラーメッセージはありません。

該当のソースコード

ここにご自身が実行したソースコードを書いてください

func receive(vc: UIViewController) {
  var storyboard = UIStoryboard(name: "Name", bundle: nil)
  if vc.storyboard === storyboard {

  } else {
    // vc.storyboardとstoryboardのアドレスは同じなのに処理はこちらにきてしまう
  }
}

イメージ説明
イメージ説明

↑2つのアドレスは同じなのに

イメージ説明
結果は違う方に行ってしまう

イメージ説明

イメージ説明

unsafeAddressOfでアドレスを取得

アドレス結果

補足情報(言語/FW/ツール等のバージョンなど)

Xcode(7.3.1)
iOS_simulator(iphone6s)

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

+2

いろいろ確認の仕方を誤って誤解しているような気がするので、コメントします。

まず、vc.storyboardのツールチップ表示とstoryboardのツールチップ表示の値が同じことから、この2つは同じだと判断しているようですが、vc.storyboardのツールチップ表示は、vc.storyboardの値を表示したものではなく、storyboardというローカル変数の値を表示しているだけです。

LLDBコマンドで
po storyboard
po vc.storyboard
の両方を打って確認すれば、ツールチップに表示されているのはstoryboardの方であることがわかると思います。まぁこれはXcodeの表示がわかりにくいと思うので、気持ちはわかりますが、大事な値を確認する時は、ツールチップ表示でなくpoコマンドで確認することをお勧めします。その方が記録も残りますし。

次に、

やはり、vc.storyboardとstoryboardは同じ実体を参照しているようです。
同じ実体だと思ってるのは画像の、0x000000010a7504b0 です。

とのことですが、0x000000010a7504b0は実体(インスタンス)ではありません。
(では、この値は何なのか?と聞かれたら、それはよくわかりません。eコマンドやpコマンドでオブジェクトを表示した時、デバッガーはそれをオブジェクトと認識せずに表示しますから、コンパイラー内部でオブジェクトを形成するための内部メモリ構造がそのまま出力されているのだと思います。その内部メモリ構造については仕様が公開されてないので正確なことはわかりません。オブジェクトを表示するならpoコマンドを使用して確認すべきだと思います。)

===演算子は、実体(インスタンス)が同じものか否かを比較する演算子ですから、
po storyboard
po vc.storyboard
の出力値が同じであれば、同じ実体(インスタンス)と判断されます。

少なくともあなたのコードは、
storyboard = UIStoryboard(name: "Main", bundle: nil)
で、新しい実体(インスタンス)を作っていますから、
それと既存のvc.storyboardの実体(インスタンス)が===で同じと判断されることは絶対にありません。

「比べたいのは、参照先の実在のストーリーボードです。」と書いている意味は、おそらく実体(インスタンス)が同じか否かを比較したいのではなく、同じストーリーボードファイルを使用して生成したものか否かを比較したいのだと思います。
既に調べられているように、どのストーリーボードファイルで使用して生成したものかを示すプロパティはないようです。今回の場合、結局は通常モードで動作しているかメンテナンスモードで動作しているかを確認したいだけのような気がするので、vcのstoryboardを生成する時に、どちらのstoryboardを生成したか(というか現在どちらのモードで動作しているか)をAppDelegateのプロパティとかに覚えておけばよいだけのように思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/07/20 01:11

    > vc.storyboardのツールチップ表示は、vc.storyboardの値を表示したものではなく、storyboardというローカル変数の値を表示しているだけです。
    よくわかりました。こちらが勝手にvc.storyboardのstoryboardにカーソルをあわせれば、うまく解釈してくれてvc.storyboardのアドレスを表示してくれてるものだと思ってたのですが、
    そうではなく、vc.storyboardのstoryboard部分がたまたまスコープ内に同名の別物のstoryboardが存在するためにこちらのアドレスが表示されてたわけですね。
    これからはツールチップではなくpoコマンドを使用していきます。

    > とのことですが、0x000000010a7504b0は実体(インスタンス)ではありません。
    ここは言葉が足りなかったです。
    0x000000010a7504b0が実体ではないことはわかります。アドレスです。
    vc.storyboardのアドレスは0x00007fbc5bd195e0番地で0x000000010a7504b0という値を格納していて、0x000000010a7504b0番地にはなにかがある。
    storyboardのアドレスは0x00007fbc5bf92b90番地で0x000000010a7504b0という値を格納していて、同じように0x000000010a7504b0番地にはなにかがある。
    つまり、同じものを指し示しているのは事実です。ここを比べたかったのです。

    > で、新しい実体(インスタンス)を作っていますから、
    それと既存のvc.storyboardの実体(インスタンス)が===で同じと判断されることは絶対にありません。
    ここはよくわかりました。

    > 同じストーリーボードファイルを使用して生成したものか否かを比較したいのだと思います。
    仰るとおりです。同じインスタンスでなくても作成元が同じならばOKです。

    > AppDelegateのプロパティとかに覚えておけばよいだけのように思います。
    これをすれば確かに実現できると思います。
    ですが、わざわざアプリ全体から参照書き換えできるプロパティを一つ用意して、状態を管理して、状態により分岐させて忘れずに状態を書き換えておく、というようなコードは避けたほうがいいかな、と思いstoryboardを利用することを思いつきました。
    ですが、比較するプロパティがないのなら、この思いつきがあまり良くなかったようです。

    今のところは、AppDelegateにlast_statusCodeプロパティを用意して実装しようと思います。

    _Kentarou様、fuzzball様、TakeOne様
    ご教授ありがとうございました。
    これからはpoコマンドを使っていきます!

    キャンセル

0

該当のソースコードをデバッグすると、同じアドレスを参照してるのに 
ifの結果はelseに飛んでしまいます。 

こちらはアドレスは違うと思います、デバックでそれぞれのアドレスを確認してみてください。
e vc.storyboarde storyboardで両方出力してみると分かると思います。

こちらのメソッドは渡されたViewControllerStoryboardを比較していますが、Storyboardが自分自身のいるStoryboardとして比較しているのでしたら、この場合はStoryboardのインスタンスを新たに作っているので同じではないです。

ロジック自体はインスタンスを渡せばちゃんと判定できています、このメソッドを使用したい状態とはどのような時でしょうか?

アドレスが同じと確認したコード

import UIKit

class ViewController1: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func pushNextButton(sender: UIButton) {

        let nextStoryboard = UIStoryboard(name: "Main2", bundle: nil)
        let vc2 = nextStoryboard.instantiateInitialViewController() as! ViewController2
        vc2.myStoryboard = nextStoryboard
        self.navigationController?.pushViewController(vc2, animated: true)
    }
}


class ViewController2: UIViewController {

    var myStoryboard: UIStoryboard!

    override func viewDidLoad() {
        super.viewDidLoad()

        receive(self)
    }

    func receive(vc: UIViewController) {

        if vc.storyboard === myStoryboard {
            print("同じ")
            //=> 同じ
        } else {
            print("違う")
        }
    }
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/07/18 11:28

    > 載せて大丈夫な画像でしたら、質問に貼り付けていただければ良いとおもいます。
    ありがとうございます。
    ソースの画像をupしました。

    キャンセル

  • 2016/07/18 12:40

    同じ事が再現するところまで作ってみました。

    画像に載ってい事は実際に起こっているのですが、それぞれのオブジェクトをprintするとアドレスは違いましたので===の判定は合っていると思います。
    ※そちらの状況とは違うかもしれません。

    この様な実装はしたことがないので詳しくは分からないです。

    こちらのプロトコルはmainViewControllerとmaintenanceViewControllerで使用していると思っていますが(mainViewControllerのあるStoryboardに配置しているもう一つのViewControllerは適用されていない想定)その場合は単純にStoryboardではなく渡されてくるViewControllerのクラスで判定するのではダメでしょうか?

    キャンセル

  • 2016/07/19 10:34

    > その場合は単純にStoryboardではなく渡されてくるViewControllerのクラスで判定するのではダメでしょうか?

    protocolはmainStoryBoardのsecondViewControllerにも適用してますので、storyboardで比較するのがスマートだと思ったのです。
    protocolをすべてのviewControllerに適用してるのは、アプリがフォアグラウンドに来る可能性はすべてのviewControllerであり得るからです。

    ですので、whetherDoMainteに渡ってくるvcはすべてのviewControllerの可能性があります。viewControllerで条件分岐するのは煩雑ですし、今後viewControllerが増えればそのたびに条件分岐のところを修正する必要があります。

    どちらのstoryboardに所属しているかがわかればviewControllerが増えたとしても修正する必要がありません。

    > それぞれのオブジェクトをprintするとアドレスは違いましたので
    こちらでもprintしてみました。
    unsafeAddressOfを使って参照元と参照先のアドレスも表示してみました。
    この確認画像もup済みです。

    やはり、vc.storyboardとstoryboardは同じ実体を参照しているようです。
    同じ実体だと思ってるのは画像の、0x000000010a7504b0 です。

    比較演算子===の挙動が全く納得いきません。

    キャンセル

0

検証は全く行っていませんので、ただのアイデアだと思って下さい。

 isEqual

if (vc.storyboard.isEqual(storyboard)) {
    print("equal")
}

 .hash

一意で有効なプロパティになるのかどうか分かりませんが。

if (vc.storyboard.hash == storyboard.hash) {
    print("equal")
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/07/19 12:59

    fuzzball様、ご回答ありがとうございます。

    isEqualも.hashもうまくいきませんでした。
    isEqualは、ステータスコードにより作られるストーリーボードの組み合わせを変えてみましたが、
    すべて場合でif文ではelse側にいってしまいます。

    .hashは数値自体が違いました。

    キャンセル

  • 2016/07/19 13:17

    残念。
    再現できる環境を作れたら調べてみるのですが、面倒臭そうなのでこれ以上はパスです。

    キャンセル

  • 2016/07/19 23:02

    ヒントを頂けただけでも嬉しいです。ありがとうございました。

    キャンセル

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

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

関連した質問

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