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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

632閲覧

delegate文のダウンキャストの意味について

momokoko

総合スコア38

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2021/02/13 06:48

編集2021/02/13 10:54

Udemyで勉強中です。
先生が書いた下記のコードについて質問が2個あります。

// FeedController.swift class FeedController: UICollectionViewController { @objc func handlelogout() { let controller = LoginController() -------質問したいコード---------- controller.delegate = self.tabBarController as! MainTabController ---------------------------- } }

前提:
・上記のコードは子のFeedController.swiftに設定され親はMainTabController。
MainTabControllerUITabBarControllerを継承。

※一番下に全体のコードが記載してあります。

質問① self.tabBarControllerに関して

FeedControllerが継承しているUICollectionViewControllerの中のメソッドにtabBarControllerはないと思うのですが、なぜself.tabBarControlleと指定できるのしょうか。

前提認識
下記のコードでself.addTargetと設定できるのはUIButtonが継承しているUIControlの中のメソッドにaddTargetがあるから。

class CustomUIButton: UIButton { init(title: String) { self.addTarget(self, action: #selector(a), for: .touchDown) } }

######質問② as! MainTabControllerについて
MainTabControllerにダウンキャストしている理由

以前の質問
以前、ダウンキャストに関する質問をしました。
今回に関しても同じような理由でダウンキャストしているのかもしれないのですが、どうしても理解することができず解説してほしいです。

以下、関係があると思われるコードです。

// FeedController.swift class FeedController: UICollectionViewController { // MARK: - Lifecycle override func viewDidLoad() { super.viewDidLoad() } @objc func handlelogout() { do { try Auth.auth().signOut() let controller = LoginController() controller.delegate = self.tabBarController as! MainTabController } catch { print("DEBUG: Failed to sing out") } } }
// LoginController.swift protocol AuthenticationDelegate:class { func authenticationDidComplete() }
// MainTabController.swift class MainTabController: UITabBarController{ // 省略 extension MainTabController: AuthenticationDelegate { func authenticationDidComplete() { print("ログインコントローラーでする処理をMainTabで処理") print("ユーザーの取得とアップデート") fetchUser() self.dismiss(animated: true, completion: nil) } } }

Udemyはアメリカの先生で英語ができないためこちらで質問させて頂いております。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TsukubaDepot

2021/02/13 10:48

delegate を強制ダウンキャストしているコードは、何かを参考にして書かれたのでしょうか。 それとも、何かの教材でしょうか。
momokoko

2021/02/13 10:53

コメントありがとうございます! Udemyになります。 質問に追記しました。
TsukubaDepot

2021/02/13 10:58

先日から気になっていたのですが、Udemy のコードの質問が多く、またその内容が必ずしも正確でないことを懸念しています。ここで回答がついた後、Udemy のコードも修正されていた、ということもありました。 これは邪推ですが、Udemy で習得されている講座そのものの正確性はどうなのでしょうか。そのあたりはご自身で問い合わせていらっしゃるのでしょうか。あまりにも正確性に欠くコードが多いようであれば、それはお金を払うに値しない場合もあるので、きちんとUdemyに訴えるべきことかと思います。 ここで付く回答は、あくまでも講座全体のコードのごく一部から推測される内容をもとにつく回答で、それは必ずしも講師の意図と一致しない場合があります。 もしかしたら、講師が全体的内容を考えた上であえてそのように教えている可能性も否定できません。 ここで質問することがダメだ、というつもりはありませんが、Udemy の講座に対して、きちんと質問すべきなのではないでしょうか(それが英語であれ日本語であれ、まずは作者に聞くのが基本だと思います)。
momokoko

2021/02/13 11:24

ご指摘ありがとうございます。 回答を頂いた後、Udemy のコードも修正されていた件については失礼いたしました。 https://teratail.com/questions/320387 こちらの質問かと思いますが、チャプターを完了し理解した上で整理したいと思っております。 (今現在の質問はそのチャプターに関する疑問点です、コメント頂いているのに閉じられずにすみません) ぼくは作りたいアプリがあり、それはインスタグラムのような画像シェアアプリです。 Udemyの講座では、まさにインスタグラムのクローンを作る講座だったので受講しました。 (https://www.udemy.com/course/instagram-firestore-app-clone-swift-5-ios-14-mvvm/) 実は、この先生の古いバージョンのインスタグラム講座(https://www.udemy.com/course/instagram-clone-w-swift-4-firebase-and-push-notifications/)を受けていてその際、先生に質問していましたが、自分の英語力のなさで理解できないまま講座を進めてしまうという失敗体験があったので今回の講座ではテラテイルを利用させて頂いております。
TsukubaDepot

2021/02/13 11:42

いや、英語力うんぬんを問うているわけではなく、「講座の中身そのものの信頼性」を聞いているのです。 日本語であれ英語であれ、文法エラーでコンパイルすら通らないテキストが講座に載っている時点で、その講座に問題があるとおもいませんか、と聞いているのです。 私も Udemy のアカウントは持っているので、リンク先の講座を見てみました。 受講の前提に - Some programming experience and knowledge of Xcode is preferred とありますが、章立てやイントロダクションを見る限り、Swift の文法書一冊を一通り読みこなした程度の知識は必要そうです。文法を理解しないでこの講座を受講するのは無理があると思います。 評価は悪くない講座ですが、高評価の多くは「最低限の言語知識は必要だ」と書いていいます。 最低評価でコメントを書いている人は一人ですが、コードは更新されないし、質問にも答えてくれない、というものもありました。 おそらく、この講座の受講者の多くは、仮にコードに間違いがあってもそれを自分で解決するだけの読解力がある人だと思っています。 もちろん、これらをどう解釈されて、どのように使われるかは質問者さんが判断することですが、テキストを見ることができない外部の回答者がどれだけ正確に答えられるかは疑問に思います。
guest

回答1

0

ベストアンサー

質問① self.tabBarControllerに関して

FeedControllerが継承しているUICollectionViewControllerの中のメソッドにtabBarControllerはないと思うのですが、なぜself.tabBarControlleと指定できるのしょうか。

FeedController の定義の冒頭を見てみると、

Swift

1class FeedController: UICollectionViewController { 2 @objc func handlelogout() {

という感じで宣言されています。

つまり、FeedControllerUICollectionViewController を親クラスとして定義されたカスタムクラスということです。

ここで、UICollectionViewControllerの定義を改めて確認したいと思います。

A view controller that specializes in managing a collection view.

このドキュメントの後半をみると、次のような行があることに気づくと思います。

Inherits From UIViewController

Inherit というのは一般的に「継承・相続」という意味です。
オブジェクト指向においても、Inherit という単語は「継承」という意味で使われます。

したがって、UICollectionViewControllerUIViewController を継承したクラスである、ということになります。

さらに、ここで UIViewController のマニュアルを見てみます。

var tabBarController: UITabBarController?

The nearest ancestor in the view controller hierarchy that is a tab bar controller.
An object that manages a view hierarchy for your UIKit app.

つまり、UIViewController にはそのクラスが備えたプロパティとして tabBarController というプロパティがある、というわけです。

したがって、UICollectionViewController が直接的に tabBarController というプロパティを持っていなくとも、継承元である UIViewController が持っているため、結果としてみることができる、ということになります。

質問② as! MainTabControllerについて
MainTabControllerにダウンキャストしている理由

これは、Udemy の講師にその意図を確認しないと正確な理由はわかりません。

Swift

1 controller.delegate = self.tabBarController as! MainTabController

という一行と、プロパティ名の慣習から想像するに、controller.delegate の型として宣言されているのは「プロトコル」だと思われます。

しかし、プロトコルに準拠させるために、このような方法で強制ダウンキャストをさせる理由は思いつきません(一応、一日考えてみましたが、妥当な理由は探せませんでした)。

一方、考えられる理由としては以下のことが考えられます。

Swift

1    self.tabBarController

は、UITabBarController を継承しているクラスであれば、どのようなクラスでも構いません。しかし、今回作っているアプリの構造として、self.tabBarController に代入された具体的なインスタンスは MainTabBarController でなければならない、という制約がある可能性はあります。

そうなると、as! を使ってここで強制的にキャストし、失敗時には実行時エラーとさせることによって、ロジックが間違っていることを早期に判断させる、という意図は考えられると思います。

一応、プロトコルにもキャストという概念はあり、たとえば swift.docs では下記のリンクで説明してあります。

上記のページでは具体的なキャストの例として、次のような例があげてあります。

Swift

1 protocol HasArea { 2 var area: Double { get } 3 } 4 5 class Circle: HasArea { 6 let pi = 3.1415927 7 var radius: Double 8 var area: Double { return pi * radius * radius } 9 init(radius: Double) { self.radius = radius } 10 } 11 class Country: HasArea { 12 var area: Double 13 init(area: Double) { self.area = area } 14 } 15 16 class Animal { 17 var legs: Int 18 init(legs: Int) { self.legs = legs } 19 } 20 21 let objects: [AnyObject] = [ 22 Circle(radius: 2.0), 23 Country(area: 243_610), 24 Animal(legs: 4) 25 ] 26 27 for object in objects { 28 if let objectWithArea = object as? HasArea { 29 print("Area is (objectWithArea.area)") 30 } else { 31 print("Something that doesn't have an area") 32 } 33 }

上記の例を見ればわかる通り、プロトコルにおける as? を使ったキャストは、クラスに対する as? を使ったダウンキャストという側面とは異なり、インスタンスが特定のプロトコルに準拠しているか否かを判断する(パターンマッチを行っている)側面を持っています。

こういう事例を考えるに、(2)で挙げられているご質問は、プロトコルに対するキャストなどではなく、単に delegate に代入する前段階として、指定したプロパティが特定の型に強制ダウンキャストできるか否かを判断している理由ではないかと推測されます。

投稿2021/02/14 13:01

編集2021/02/19 06:26
TsukubaDepot

総合スコア5086

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

momokoko

2021/02/15 05:36

ありがとうございます。 質問①について、理解しました。 取り急ぎお礼を申し上げます。
momokoko

2021/02/19 06:37 編集

質問②について、推測までしていただきありがとうございます。 質問の不足まで補完していただけたご回答、感謝申し上げます。 以下、今回の質問で学んだことをまとめさせていただきます。 let controller = LoginController() controller.delegate = self.tabBarController as! MainTabController 上記コードの意味 LoginController()が持つ、delegateプロパティにMainTabControllerにキャストさせた self.tabBarControllerを代入している。 なぜキャストするか。(推測) ・delegateプロパティがMainTabController型だから ・self.tabBarController がMainTabControllerにキャストできるかどうかでエラーを未然に防ぐため。
TsukubaDepot

2021/02/19 06:45

delegate に対するキャストについては、本当に推測なので忘れた方がいいかもしれません(こういう意図でキャストした例は、私の少ない事例だと思い出せません)。取得されているコースが MVVM まで教えているコースなので、もしかしたら意図しない View Controller を代入させない目的でこのような使い方をしたのかもしれませんが、はやり推測の域を出ませんので...
momokoko

2021/02/19 07:19

なるほど、お気遣いありがとうございます。 今の僕では回答頂いたことが正しいか確認もできませんが、よくわからないコードがそこにあるよりも、なんとなく自分なりの答えも持っていた方が後から似たようなコードに出会ったときに紐付けて理解できると思っています。 今回の質問は、回答頂いた理由が正しいかわからないものの、次回似たようなコードがあった際は、最初に検討できる理由を知れたので良い知識を手に入れたと思っております。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問