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

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

ただいまの
回答率

89.09%

なぜクロージャの外でAddSubViewするコードが多いのか?

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 527

hodoru3sei

score 122

クロージャを使ってそのなかでViewの詳細を定義する書き方を見かけます。
下記の例ではTaskButtonに一度格納してクロージャの外でaddSubViewしていますが、クロージャの中で全てをやってしまいたいと考えました。

let TaskButton:UIButton = {
            let button = UIButton()
            button.layer.masksToBounds = true
            button.layer.cornerRadius = 50.0
            button.frame = CGRect(x:0,y:0,width:self.view.frame.width/4,height:self.view.frame.width/4)
            button.backgroundColor = .red
            button.layer.position = CGPoint(x: self.view.frame.midX, y: self.view.frame.height - self.view.frame.midY)
            button.setTitle("追加", for: UIControlState.normal)
            button.addTarget(self, action:
                #selector(addTask), for: .touchUpInside)
            return button
        }()
        self.view.addSubview(TaskButton)

クロージャの中で全てやってしまうコード

var _ = { ()->() in
            let button = UIButton()
            button.frame = CGRect(x:0,y:0,width:self.view.frame.width/4,height:self.view.frame.width/4)
            button.backgroundColor = .red
            button.layer.position = CGPoint(x: self.view.frame.midX, y: self.view.frame.midY)
            button.setTitle("ボタン", for: UIControl.State.normal)
            self.view.addSubview(button)
        }()

クロージャの中でaddSubViewまでやってしまうコードをネットでみたことがありません、何が問題があるのでしょうか?
個人的にはクロージャの中でaddSubViewまでやったほうが綺麗な気がしたのに例を見つけられなかったので疑問に思いました。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+1

基本UIはCustomView以外Storyboardでほとんど済ませるので個人的な見解になりますが、

上記の例ではUIButtonの生成とそのプロパティの割り当てだけと割り切っています。ですが、下記の例のようにself.view.addSubview(button) まで入れてしまうとTaskButtonは自身だけでなくviewまで抱え込んでしまうことになります。どちらがより疎であるか、という点を考えた場合、下記の例よりも上記の例の方がより疎であるといえるでしょう。なのでself.view.addSubview(button) は外にあるのではないでしょうか。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/09/24 20:52

    TaskBottonもButtonというViewの一種なのだと思っていました。
    MVCをまだ理解できていないのですが、もしかしてTaskButtonをControllerクラスで生成してaddSubViewはViewクラスで実装するみたいに分けることができなくなってしまうので上記の例の方が良いってことなのでしょうか

    キャンセル

  • 2018/09/24 21:53

    UIViewのの一種、と言うよりはTaskButtonはUIButtonで宣言されてますし、クロージャ内でUIButtonを返していますのでUIButtonそのものですね。
    うーん、addSubViewは多分UIViewControllerでやるものだと思うのでちょっと違う気がしますが、

    > 分けることができなくなってしまう

    この部分は正しいですし、考え方のベクトルもあってると思います。もしかしたら感覚的な理解かもしれませんが大事な部分です。
    MVCもそうですしModel同士、View同士、Controller同士でも疎結合であればあるほど良いとされています。疎結合というのは簡単に言えば二者間の関連性が薄いことです。疎結合であれば片方に変更があった場合もう片方に対する影響が少なくてすみます。逆に密結合である場合、片方に変更があった場合もう片方にも大きな変更を余儀なくされることがあります。

    なので

    > 分けることができなくなってしまう

    ようなコードは避けた方が、プロジェクトメンバーにとっても優しいのはもちろん、自分自身にとってもメリットが大きいですよ。

    あとコメントしていて気づいたのですが下記の例だと変数名がないのでremoveFromSuperViewが出来ないですね。

    キャンセル

  • 2018/09/25 09:36

    >>TaskBottonもButtonというViewの一種なのだと思っていました。

    xAxisさんの言っているviewはself.viewのことじゃないですかね。
    で、addSubViewはself.viewがやることなので、TaskButtonの処理に含めるべきではないと思います。(どうでもいいですが、変数名はtaskButtonの方がいいと思います)
    下のコードってクロージャにする意味あるの?って思ってしまいますが‥。

    ちなみに私は(今のところ)クロージャは使わない派です。(関数化します)

    キャンセル

  • 2018/09/25 09:52

    >> fuzzballさん
    いつも補足ありがとうございます。

    > xAxisさんの言っているviewはself.viewのこと

    はおっしゃる通りです。言葉足らずでした。

    > ちなみに私は(今のところ)クロージャは使わない派です。(関数化します)

    自分もUIに関してはCustomClassで関数化しちゃいます。他の場面でもほとんど関数化しちゃいますね。クロージャを使う場面といったら関数内で使う事があるくらいです。

    キャンセル

+1

参考程度ですが、私は中に書いてしまう事が多いです。
昔のiOSではViewControllerのviewは非表示かつメモリ不足時に破棄されるという仕様だったため、
viewに紐付いているコントロールもメンバで保持する場合はweakにすべきという風習がありました。

そのためその頃の名残で今でも

private weak var hogeButton: UIButton?

override loadView() {
    super.loadView()

    hogeButton = {
        let b = UIButton()
        ....
        view.addSubview(b)
        return b
    }()
}

などと書く癖が残っています。
弱参照なので、一度viewに追加して参照カウンタを増やしてからでないと代入できないためです。

今、この時代にわざわざこの方法(弱参照で保持)を採る必要はありませんので、あくまでご参考まで。

※ちなみに中でも外でも言うほどの差は無いと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

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