メインコンテンツへスキップ
見出し画像

【じっくりSw1ftUI 24】Essentials第11章〜Playgroundで遊ぼう⑩サブクラスと拡張。既存の機能なんかに独自機能を追加して遊ぼう

    さてと、前回

    で、

    Class(クラス)の基本

    はやったので、今回は、そのクラスを基本に

    • サブクラス=継承

    • エクステンション=拡張

    に入ってく〜〜〜

    画像
    略して、Essentials

    の第11章の流れに沿って、自分の学びで

    英語力が落ちないように
    サンプルコードなんかを適当に作って動かしてるだけが基本

    だから、

    本編の内容を、日本語でじっくり学習したい

    って人は、前回の調べ物の合間に発見した

    でやった方が早いので、そちらでどうぞ〜〜〜。
    *オイラが作ったサイトでもないし、公式なものかもどうか知らないけどね👀💦

    さてと、

    第11章をじっくり読んでく

    概要では、

    親クラスとかスーパークラスってやつを元にして、
    サブクラスってのが組めるぜ!

    って感じの紹介をしてるね。前回やったプロトコルも

    クラスなんかに適用して、プロトコルの機能を流用してたあのイメージ

    第1節では、

    継承と、クラスと、サブクラスと。。。

    てタイトルになっていて、JavaとかJavaScriptみたいなオブジェクト志向言語をやったことがある人には、

    いつものあれ

    って感じでイメージはすぐに湧くと思うんだけど、

    基本クラス(ルートクラス)を継承して、
    サブクラスとか子クラスでその機能を動かすことができる

    って説明をしてんね👀と、(ちょっと話が脱線して、)メリットとしては〜

    一回書いた機能を他の箇所でも使うのに、
    何回も同じこと書くのは面倒くさいし〜〜〜

    で、

    再利用できるようにしたのがClass

    って概念って思ってもらえればここでは充分。

    👉前章では、再利用する元となる親クラスを作ってた

    ってことに他ならないんだよね〜〜〜
    (※プロトコルに関しては、クラスみたいに自分で作成出来なくもないんだけど、元々公開してるAPI(ライブラリ)を使うことが殆どだし、それをクラス自体に適用するだけだから、ちょっと話してる毛色が異なる👀💦
    ①プロトコル
    ↓
    ②スーパークラスに何かのプロトコルを適用
    ↓
    ③必要があればサブクラスにプロトコルを適用したスーパークラスを使う

    みたいな流れになるからね。)

    とここで、この節の後半でも書いてるんだけど、

    別に、

    ①親クラスを作る
    ↓
    ②子クラスを作って親クラスを継承する
    👉子クラスを作るには親クラスが必要だ

    みたいなイメージを勝手に即断即決で思い込んでしまう人もいるんだけど、そんなことはなくて、

    親と子の関係ってゆーのは要は、なんかの時に

    1. 継承される側のクラス=親クラス

    2. 継承する側のクラス=子クラス

    ってだけの関係で、

    ①元々、独自で複数のクラスが存在
    ↓
    ②何かの時に、元々あるクラスを継承(機能を流用)して作った方が、
    同じコードを再度、書かなくて済む
    ↓
    ⭐️同じ機能のコードが複数存在するのは、読みにくくなって可読性(読みやすさ)も落ちて、バグの素
    ↓
    ③あのクラスの機能をそのまま他のクラスの中で使えたら便利じゃん

    👉オブジェクト志向言語の醍醐味=再利用

    ってだけのイメージ。

    ま、そこにアクセスできる範囲=スコープ(だったかな)

    なんかで、他で再利用できないとか、同じファイルの中でしか再利用できないように隠蔽なんかをさせることもできるんだけど

    そこは、この本を読み進めても出てくると思うから、あえてここでは触れない。。。💦

    と、上記の勝手な思い込みについては、アクセスのクエリデザインで

    左外部結合は、

    • 結合元のテーブル=左、LEFT。0で表現されることが多い

    • 結合先のテーブル=1で表現されることが多い

    ってだけの関係なのに、

    元のテーブルは左側に置かないといけない

    みたいな先入観で、ER図なんかもなんか知らないけど、左から右に綺麗な樹形図になって、右側だけクエリがパンパンみたいな分かりにくいクエリを作ってしまう人も多いから気をつけてね〜〜〜

    👉クエリデザインの位置とテーブルの結合関係には何の関係もない。

    結合先のテーブルを右側に置いても、左側においても、結合関係がしっかり出来ておけば、動きは一緒だから。
    さてと、本編に戻って、ここからは

    前章で作ったクラス

    class ProfileAccount10_1 {
        //ストアドプロパティ
        var m_KakuAge: Int = 43
        var m_KakuWeight: Float = 68.9//キログラム
        var m_KakuHeight: Float = 1.7//メートル
        var himanFlg: Bool = false
        var notFatFlg: Bool = true
        //コンピューテッドプロパティ:BMI計算
        var calcBMI: Float {
            get {
                return m_KakuWeight / (m_KakuHeight * m_KakuHeight)
            }
            set(resultBMI) {
                if resultBMI > 25 {
                    himanFlg = true
                } else {
                    himanFlg = false
                }
            }
        }
        //コンピューテッドプロパティ:肥満未満の体重上限
        var nonFatMyWeight: Float {
            get {
                return 25 * (m_KakuHeight * m_KakuHeight)
            }
            set(weightFatResult) {
                if weightFatResult - m_KakuWeight > 0 {
                    notFatFlg = true
                } else {
                    himanFlg = false
                }
            }
        }
        //イニシャライザ
        init(m_KakuAge: Int, m_KakuWeight: Float) {
            self.m_KakuAge = m_KakuAge
            self.m_KakuWeight = m_KakuWeight
        }
        //デイニシャライザ
        deinit{
            print("deinit")
        }
        //タイプメソッド
        func msgMyProfile(){
            print("オイラは\(m_KakuAge)のおっさんだぞ")
            print("オイラの体重は\(m_KakuWeight)だよ。運動せんと、、、💦")
        }
        //インスタンスメソッド
        class func getMinimunWeight() -> Float {
            return 49.9
        }
    }

    を例に、まずは、

    継承する側=サブクラス

    を作る。ま、適当に

    class M_Kaku_Private11_1: ProfileAccount10_1{
        
    }

    てな感じでサブクラスを用意。
    これを見るだけでも、

    sub class M_Kaku_Private11_1: ProfileAccount10_1{
        
    }

    みたいな感じで、

    サブクラスと明確に定義しないといけないものではない
    👉要は、他のクラスの機能をただ流用するために便宜的に適用すればOK

    ってのがわかると思う👀🕺実際、サブクラスだからってすぐ上みたいなコードを書くと、、、

    画像
    てな感じでエラーになる

    sub classなんて書き方(予約語)がSwiftの元々の機能でないから

    親クラスであろうが、子クラスであろうが純粋に、

    クラスはclassと表現する

    こうも親、子って言葉が続くと何故か親亀、子亀って感じでイメージする人もいるんだけど、

    全く関係ないので言葉だけで勝手にイメージしないでね、、、

    • 別に親クラスが親亀のようにコケたところで、継承さえ無くして仕舞えば子クラスに影響はなくなる。

    • 生物の親子関係は変えることができなくても、プログラミングの子クラスはいつでも親クラスにすることもできる。

    ので、、、💦あくまでも、

    👉継承の範囲で、一時的に影響し合ってるってだけの話

    さて、

    サブクラスに変数を定義

    class M_Kaku_Private11_1: ProfileAccount10_1{
        //足のサイズ(センチメートル)
        var myFootSize: Float = 27.0
    }

    サブクラスに関数を追加して実行

    class M_Kaku_Private11_1: ProfileAccount10_1{
        //足のサイズ(センチメートル)
        var myFootSize: Float = 27.0
        
        //意味はないけど、足のサイズに身長をかけてみた
        func calc() -> Float {
            return myFootSize * m_KakuHeight
        }
    }
    var myFoot11_1: M_Kaku_Private11_1 = M_Kaku_Private11_1(m_KakuAge: 43, m_KakuWeight: 59.1)
    print("足のサイズ(cm)*身長は、\(myFoot11_1.calc())")
    画像
    てな感じで〜〜〜さらに、、

    オーバーライド

    もできるんだけど、そもそも

    オーバーライドとはなんぞ?
    (麿に教えて給れ)

    って人もいるとは思うので〜〜〜

    を見ると、オーバーライドとは、

    ”オブジェクト指向プログラミングにおいて用いられるコーディングであり、親クラスで定義されたメソッドを子クラスで再度定義することで、メソッドを上書きし機能を変更すること
    👉これはオブジェクト指向プログラミングによるポリモーフィズム(多態性)を表現する上でも、基本的な方法”

    ってことらしい。普段何気なくやってんだけど、言葉にするとなるほどって感じだね👀
    てゆーて、オブジェクト志向言語をやったことがない人には説明ではイメージが湧かないと思うので〜〜〜

    class M_Kaku_Private11_1: ProfileAccount10_1{
        //足のサイズ(センチメートル)
        var myFootSize: Float = 27.0
        
        //意味はないけど、足のサイズに身長をかけてみた
        func calc() -> Float {
            return myFootSize * m_KakuHeight
        }
        //オーバーライド
            override func msgMyProfile(){
                print("オイラは\(m_KakuAge)のおっさんだぞ")
                print("オイラの体重は\(m_KakuWeight)だよ。運動せんと、、、💦")
                //ここに親クラスのメソッドを流用して追加
                print("足のサイズ(cm)は、\(myFootSize)だよ。")
            }
    }
    var myFoot11_1: M_Kaku_Private11_1 = M_Kaku_Private11_1(m_KakuAge: 43, m_KakuWeight: 59.1)
    print("足のサイズ(cm)*身長は、\(myFoot11_1.calc())")
    myFoot11_1.msgMyProfile()
    画像
    みたいなこともできるし~~~

    親クラスのメソッドを

    superでそのまま呼び出して〜〜〜

    class M_Kaku_Private11_1: ProfileAccount10_1{
        //足のサイズ(センチメートル)
        var myFootSize: Float = 27.0
        //意味はないけど、足のサイズに身長をかけてみた
        func calc() -> Float {
            return myFootSize * m_KakuHeight
        }
        //オーバーライド
        override func msgMyProfile(){
    //        print("オイラは\(m_KakuAge)のおっさんだぞ")
    //        print("オイラの体重は\(m_KakuWeight)だよ。運動せんと、、、💦")
            //スーパーさんを使う
            super.msgMyProfile()
            //ここに親クラスのメソッドを流用して追加
            print("足のサイズ(cm)は、\(myFootSize)だよ。")
        }
    }
    var myFoot11_1: M_Kaku_Private11_1 = M_Kaku_Private11_1(m_KakuAge: 43, m_KakuWeight: 59.1)
    print("足のサイズ(cm)*身長は、\(myFoot11_1.calc())")
    myFoot11_1.msgMyProfile()
    画像
    結果はもちろん一緒〜〜〜

    イニシャライザ

    を継承することも可能〜〜〜

    class M_Kaku_Private11_1: ProfileAccount10_1{
        //足のサイズ(センチメートル)
        var myFootSize: Float = 27.0
        //イニシャライザ
        init(age:Int, weight: Float, foot:Float) {
            myFootSize = foot
            super.init(m_KakuAge: 43, m_KakuWeight: 59.1)
        }
        //意味はないけど、足のサイズに身長をかけてみた
        func calc() -> Float {
            return myFootSize * m_KakuHeight
        }
        //オーバーライド
        override func msgMyProfile(){
    //        print("オイラは\(m_KakuAge)のおっさんだぞ")
    //        print("オイラの体重は\(m_KakuWeight)だよ。運動せんと、、、💦")
            //スーパーさんを使う
            super.msgMyProfile()
            //ここに親クラスのメソッドを流用して追加
            print("足のサイズ(cm)は、\(myFootSize)だよ。")
        }
    }

    ここで作ったイニシャライザを実行するコードだと〜〜〜

    var myFoot: M_Kaku_Private11_1 = M_Kaku_Private11_1(age: 43, weight: 59.1, foot: 27.0)
    print("足のサイズ(cm)x 身長(m)は、\(myFoot.calc())")

    てな感じで〜〜実際に、実行すると、

    画像
    てな感じで、実行できてるのがわかると思う〜〜〜

    サブクラスの継承までは、ここまでらしい。
    ちょっとコードが気に入らないので、ちょいと手直しして〜〜〜

    ここまでのコードまとめ

    class M_Kaku_Private11_1: ProfileAccount10_1{
        //足のサイズ(センチメートル)
        var myFootSize: Float = 27.0
        //イニシャライザ
        init(age:Int, weight: Float, foot:Float) {
            myFootSize = foot
            super.init(m_KakuAge: 43, m_KakuWeight: 59.1)
        }
        //意味はないけど、足のサイズに身長をかけてみた
        func calc() -> Float {
            return myFootSize * m_KakuHeight
        }
        //オーバーライド
        override func msgMyProfile(){
            //        print("オイラは\(m_KakuAge)のおっさんだぞ")
            //        print("オイラの体重は\(m_KakuWeight)だよ。運動せんと、、、💦")
            //スーパーさんを使う
            super.msgMyProfile()
            //ここに親クラスのメソッドを流用して追加
            print("足のサイズ(cm)は、\(myFootSize)だよ。")
        }
    }
    var myFoot11_1: M_Kaku_Private11_1 = M_Kaku_Private11_1(age: 43, weight: 59.1, foot: 27.0)
    print("足のサイズ(cm)x 身長(m)は、\(myFoot11_1.calc())")
    myFoot11_1.msgMyProfile()

    拡張(エクステンション)

    (ちょっと、毛色が違うので大見出しにしたけど、)

    サブクラスへ継承を使わずに、元々あるクラスの機能を拡張して、
    新しい機能を作り出すこともできる
    👉ただ、この後のサンプルだと、
    Swiftフレームワークの機能を拡張する例として使ってんね
    👀

    構文

    extension ClassName {
     //拡張時の処理
    }

    円の計算をここではFloatに拡張してみる〜〜〜

    ま、円周率pi自体は、

    https://www.choge-blog.com/programming/swiftpiget/

    てな感じで取得するから、あくまでもここでの教室事例ってことで〜〜〜

    //拡張
    extension Float{
        var circleAround: Float{
            return self * 3.14159265359
        }
        var circleArea: Float{
            return self * self * 3.14159265359
        }
    }
    //実行
    let myCircle11_2: Float = 2
    print(myCircle11_2)
    print(myCircle11_2.circleAround)
    print(myCircle11_2.circleArea)

    てな感じで〜〜〜

    画像
    拡張できた〜〜〜

    ただし、見てわかると思うんだけど

    あんまり拡張を使いすぎると、

    Swiftの本来の機能に機能を組み込んでくわけだから、
    きちんと管理しないと、
    ただのデータ型Floatのはずが、何かおかしな機能が入ってないか?
    バグってるのか?
    👉怖くて使えない

    みたいなことになるので、

    却ってバグを誘発することになる。

    「単純にデータ型を定義しただけのはずなのに、コーディングミスで.(ドット)を気づかずに押してて、計算結果が全然違うモノになった」

    とかになったら大変だからね。

    今回のコードまとめ

    class ProfileAccount10_1 {
        //ストアドプロパティ
        var m_KakuAge: Int = 43
        var m_KakuWeight: Float = 68.9//キログラム
        var m_KakuHeight: Float = 1.7//メートル
        var himanFlg: Bool = false
        var notFatFlg: Bool = true
        //コンピューテッドプロパティ:BMI計算
        var calcBMI: Float {
            get {
                return m_KakuWeight / (m_KakuHeight * m_KakuHeight)
            }
            set(resultBMI) {
                if resultBMI > 25 {
                    himanFlg = true
                } else {
                    himanFlg = false
                }
            }
        }
        //コンピューテッドプロパティ:肥満未満の体重上限
        var nonFatMyWeight: Float {
            get {
                return 25 * (m_KakuHeight * m_KakuHeight)
            }
            set(weightFatResult) {
                if weightFatResult - m_KakuWeight > 0 {
                    notFatFlg = true
                } else {
                    himanFlg = false
                }
            }
        }
        //イニシャライザ
        init(m_KakuAge: Int, m_KakuWeight: Float) {
            self.m_KakuAge = m_KakuAge
            self.m_KakuWeight = m_KakuWeight
        }
        //デイニシャライザ
        deinit{
            print("deinit")
        }
        //タイプメソッド
        func msgMyProfile(){
            print("オイラは\(m_KakuAge)のおっさんだぞ")
            print("オイラの体重は\(m_KakuWeight)だよ。運動せんと、、、💦")
        }
        //インスタンスメソッド
        class func getMinimunWeight() -> Float {
            return 49.9
        }
    }
    
    class M_Kaku_Private11_1: ProfileAccount10_1{
        //足のサイズ(センチメートル)
        var myFootSize: Float = 27.0
        //イニシャライザ
        init(age:Int, weight: Float, foot:Float) {
            myFootSize = foot
            super.init(m_KakuAge: 43, m_KakuWeight: 59.1)
        }
        //意味はないけど、足のサイズに身長をかけてみた
        func calc() -> Float {
            return myFootSize * m_KakuHeight
        }
        //オーバーライド
        override func msgMyProfile(){
            //        print("オイラは\(m_KakuAge)のおっさんだぞ")
            //        print("オイラの体重は\(m_KakuWeight)だよ。運動せんと、、、💦")
            //スーパーさんを使う
            super.msgMyProfile()
            //ここに親クラスのメソッドを流用して追加
            print("足のサイズ(cm)は、\(myFootSize)だよ。")
        }
    }
    var myFoot11_1: M_Kaku_Private11_1 = M_Kaku_Private11_1(age: 43, weight: 59.1, foot: 27.0)
    print("足のサイズ(cm)x 身長(m)は、\(myFoot11_1.calc())")
    myFoot11_1.msgMyProfile()
    
    //拡張
    extension Float{
        var circleAround: Float{
            return self * 3.14159265359
        }
        var circleArea: Float{
            return self * self * 3.14159265359
        }
    }
    //実行
    let myCircle11_2: Float = 2
    print(myCircle11_2)
    print(myCircle11_2.circleAround)
    print(myCircle11_2.circleArea)

    再利用してるから、他の記事の普段のコードに比べても、

    めちゃくちゃ短いし、シンプルでしょ👀

    まとめ

    ここでは本編でも

    ”○継承:既存のクラスから新しいクラスを派生できるようにすることで、オブジェクト指向プログラミングにおけるオブジェクトの再利用の概念を拡張し、その後、それらの新しいクラスを拡張して新しい機能を追加
    👉継承により、そのクラスを新しいサブクラスの基礎として使用できるようになる。
    新しいサブクラスは親クラスのすべての機能を継承しますが、不足している機能を追加するために拡張できる。
    ○拡張:サブクラスを作成せずに既存のクラスに機能を追加する便利な代替オプションを提供。”

    って書いてるとおり、元々あるクラスやSwift本来の機能なんかを

    再利用

    して、

    新たな独自の処理なんかを追加できるんだ
    👉元々(何かしら)ある機能(処理)に、何かを追加したいときに使うんだ!

    ってイメージしてもらえれば今は充分。
    ま、JavaとかC、JavaScriptくらいが大好き(逆にそれしか知らない)なレガシーエンジニアさんなんかで、

    Swiftは簡単=できることが少ない

    みたいな固定観念を持って、

    Javaが出来たら今のプログラミングの基本が全て身に付く

    なんて豪語する人もいるんだけど、別に、

    Swiftもオブジェクト志向言語である限り、
    再利用できるのは変わらないんだけどね
    👀💦
    VBAですら変わらない

    むしろ、Javaの基本理念の

    one write,run everywhere

    に騙されて、JavaでiOSアプリなんかを作るより、iOSを出して管理してる会社=Appleが作ってる専用の最新言語でアプリは作った方が作業コストはグッと減る🕺

    Javaは確かにある程度のツールを作ることはできるけど、専用の言語と比べて、やらないといけないことも多いし、よく言われるのが、

    カッターで大木を切る

    くらい専用の言語に比べると中途半端で効率が悪いことが多いからね。それでもJavaを崇めてるのは、

    他のプログラミング言語を深く学んでないか、知らない人だけ。

    ま、それに騙されて、今でも日本の国家資格(情報技術者系)なんかではJavaとC、WEBとCOBOLだけ教えて、国家資格だから、他の言語より凄いなんて勘違いしてる人も見るけどね。どの言語も

    • スマホアプリ系なら、Swift(iOS)かKotlin(Android)だし、

    • WEB系ならJavaScript、

    • エクセルなどのオフィスソフト系なら、VBA

    • WEBまで含めた自動化ロボを作るならUiPathやWInActorといったRPA

    て感じで、一長一短があるから、逆に

    この言語が一番
    みたいな優劣を決めたがる

    時点で、エンジニアとかクリエイターからしたら、

    素人さんかな?👀💦

    としか思わないけどね。

    さてと、次回は

    のコードテンプレートで、毎回、記事公開後にやってるコードでふんだんに使ってる

    構造体:struct
    列挙型:enum

    を扱った12章に入ってく〜〜〜🕺

    前回までのサンプルコードをちゃんと動かしながら読んでる人にはわかるとは思うけど、

    SwiftUIファイルを新規で作成した場合の、初期コード自体が、

    struct

    だから、

    構造体の理解=SwiftUIフレームワークの基本中の基本

    ってことで💦

    じゃ、また次回!!!!

    記事公開後、

    でやってる作業を今回も!

    画像
    久しぶりに横向き〜〜〜
    画像
    てな感じで〜〜〜
    画像
    WEBのみ縦〜〜〜🕺

    コード

    iOSApp17DevelopmentEssentials

    
    import SwiftUI
    
    //ビュー管理構造体
    struct ListiOSApp17DevelopmentEssentials: Identifiable {
        var id: Int
        var title: String
        var view: ViewEnumiOSApp17DevelopmentEssentials
    }
    
    //遷移先の画面を格納する列挙型
    enum ViewEnumiOSApp17DevelopmentEssentials {
        case Ch1
        //じっくり13で追加
        case Ch2
        //じっくり13で追加
        case Ch3
        //じっくり15で追加
        case Ch4
        //じっくり16で追加
        case Ch5
        //じっくり17で追加
        case Ch6
        //じっくり18で追加
        case Ch7
        //じっくり19で追加
        case Ch8
        //じっくり20、21で追加
        case Ch9
        //じっくり22、23で追加
        case Ch10
        //じっくり24で追加
        case Ch11
    }
    
    //各項目に表示する文字列
    let dataiOSApp17DevelopmentEssentials: [ListiOSApp17DevelopmentEssentials] = [
        ListiOSApp17DevelopmentEssentials(id: 1, title: "第1章", view: .Ch1),
        //じっくり13で追加
        ListiOSApp17DevelopmentEssentials(id: 2, title: "第2章", view: .Ch2),
        //じっくり13で追加
        ListiOSApp17DevelopmentEssentials(id: 3, title: "第3章", view: .Ch3),
        //じっくり15で追加
        ListiOSApp17DevelopmentEssentials(id: 4, title: "第4章", view: .Ch4),
        //じっくり16で追加
        ListiOSApp17DevelopmentEssentials(id: 5, title: "第5章", view: .Ch5),
        //じっくり17で追加
        ListiOSApp17DevelopmentEssentials(id: 6, title: "第6章", view: .Ch6),
        //じっくり18で追加
        ListiOSApp17DevelopmentEssentials(id: 7, title: "第7章", view: .Ch7),
        //じっくり19で追加
        ListiOSApp17DevelopmentEssentials(id: 8, title: "第8章", view: .Ch8),
        //じっくり20、21で追加
        ListiOSApp17DevelopmentEssentials(id: 9, title: "第9章", view: .Ch9),
        //じっくり22、23で追加
        ListiOSApp17DevelopmentEssentials(id: 10, title: "第10章", view: .Ch10),
        //じっくり24で追加
        ListiOSApp17DevelopmentEssentials(id: 11, title: "第11章", view: .Ch11)
    ]
    
    struct iOSApp17DevelopmentEssentials: View {
        var body: some View {
            VStack {
                Divider()
                List (dataiOSApp17DevelopmentEssentials) { data in
                    self.containedViewiOSApp17DevelopmentEssentials(dataiOSApp17DevelopmentEssentials: data)
                }
                .edgesIgnoringSafeArea([.bottom])
            }
            .navigationTitle("iOS開発の章目次")
            .navigationBarTitleDisplayMode(.inline)
        }
        //タップ後に遷移先へ遷移させる関数
        func containedViewiOSApp17DevelopmentEssentials(dataiOSApp17DevelopmentEssentials: ListiOSApp17DevelopmentEssentials) -> AnyView {
            switch dataiOSApp17DevelopmentEssentials.view {
            case .Ch1:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh1()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり13で追加
            case .Ch2:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh2()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり13で追加
            case .Ch3:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh3()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり15で追加
            case .Ch4:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh4()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり16で追加
            case .Ch5:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh5()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり17で追加
            case .Ch6:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh6()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり18で追加
            case .Ch7:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh7()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり19で追加
            case .Ch8:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh8()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり20、21で追加
            case .Ch9:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh9()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり22、23で追加
            case .Ch10:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh10()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
            case .Ch11:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh11()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
            }
        }
    }
     #Preview  {
        iOSApp17DevelopmentEssentials()
    }

    iOSApp17DevelopmentEssentialsCh11

    import SwiftUI
    
    //ビュー管理構造体
    struct ListiOSApp17DevelopmentEssentialsCh11: Identifiable {
        var id: Int
        var title: String
        var view: ViewEnumiOSApp17DevelopmentEssentialsCh8
    }
    
    //遷移先の画面を格納する列挙型
    enum ViewEnumiOSApp17DevelopmentEssentialsCh11 {
        case Sec1
    }
    
    //各項目に表示するリスト項目
    let dataiOSApp17DevelopmentEssentialsCh11: [ListiOSApp17DevelopmentEssentialsCh11] = [
        ListiOSApp17DevelopmentEssentialsCh11(id: 1, title: "第1節", view: .Sec1)
    ]
    
    struct iOSApp17DevelopmentEssentialsCh11: View {
        var body: some View {
            VStack {
                Divider()
                List (dataiOSApp17DevelopmentEssentialsCh11) { data in
                    self.containedViewiOSApp17DevelopmentEssentialsCh11(dataiOSApp17DevelopmentEssentialsCh11: data)
                }
                .edgesIgnoringSafeArea([.bottom])
            }
            .navigationTitle("11章目次")
            .navigationBarTitleDisplayMode(.inline)
        }
        //タップ後に遷移先へ遷移させる関数
        func containedViewiOSApp17DevelopmentEssentialsCh11(dataiOSApp17DevelopmentEssentialsCh11: ListiOSApp17DevelopmentEssentialsCh11) -> AnyView {
            switch dataiOSApp17DevelopmentEssentialsCh11.view {
            case .Sec1:
                return AnyView(NavigationLink (destination: Essentials11()) {
                    Text(dataiOSApp17DevelopmentEssentialsCh11.title)
                })
            }
        }
    }
     #Preview  {
        iOSApp17DevelopmentEssentialsCh11()
    }

    Essentials11

    import SwiftUI
    import WebKit
    
    struct Essentials11: View {
        var body: some View {
            VStack{
                TabView {
                    Essentials11Code()
                        .tabItem {
                            Image(systemName: codeImageTab)
                            Text(codeTextTab)
                        }
                    Essentials11Points()
                        .tabItem {
                            Image(systemName: pointImageTab)
                            Text(pointTextTab)
                        }
                    Essentials11WEB()
                        .tabItem {
                            Image(systemName: webImageTab)
                            Text(webTextTab)
                        }
                }
            }
        }
    }
     #Preview  {
        Essentials11()
    }
    
    struct Essentials11Code: View {
        var body: some View {
            ScrollView{
                Text(codeEssentials11)
            }
        }
    }
     #Preview  {
        Essentials11Code()
    }
    
    struct Essentials11Points: View {
        var body: some View {
            ScrollView{
                Text(pointEssentials11)
            }
        }
    }
     #Preview  {
        Essentials11Points()
    }
    
    struct Essentials11WebView: UIViewRepresentable {
        let searchURL: URL
        func makeUIView(context: Context) -> WKWebView {
            let view = WKWebView()
            let request = URLRequest(url: searchURL)
            view.load(request)
            return view
        }
        
        func updateUIView(_ uiView: WKWebView, context: Context) {
            
        }
    }
    
    struct Essentials11WEB: View {
        private var url:URL = URL(string: urlEssentials11)!
        var body: some View {
            Essentials11WebView(searchURL: url)
        }
    }
     #Preview  {
        Essentials11WEB()
    }
    

    CodeManageFile(追加分のみ)

    let codeEssentials11 = """
    /**:-------------------
     Essentials 第11章 サブクラスと拡張の説明
     ---------------------*/
    class ProfileAccount10_1 {
        //ストアドプロパティ
        var m_KakuAge: Int = 43
        var m_KakuWeight: Float = 68.9//キログラム
        var m_KakuHeight: Float = 1.7//メートル
        var himanFlg: Bool = false
        var notFatFlg: Bool = true
        //コンピューテッドプロパティ:BMI計算
        var calcBMI: Float {
            get {
                return m_KakuWeight / (m_KakuHeight * m_KakuHeight)
            }
            set(resultBMI) {
                if resultBMI > 25 {
                    himanFlg = true
                } else {
                    himanFlg = false
                }
            }
        }
        //コンピューテッドプロパティ:肥満未満の体重上限
        var nonFatMyWeight: Float {
            get {
                return 25 * (m_KakuHeight * m_KakuHeight)
            }
            set(weightFatResult) {
                if weightFatResult - m_KakuWeight > 0 {
                    notFatFlg = true
                } else {
                    himanFlg = false
                }
            }
        }
        //イニシャライザ
        init(m_KakuAge: Int, m_KakuWeight: Float) {
            self.m_KakuAge = m_KakuAge
            self.m_KakuWeight = m_KakuWeight
        }
        //デイニシャライザ
        deinit{
            print("deinit")
        }
        //タイプメソッド
        func msgMyProfile(){
            print("オイラは\\(m_KakuAge)のおっさんだぞ")
            print("オイラの体重は\\(m_KakuWeight)だよ。運動せんと、、、💦")
        }
        //インスタンスメソッド
        class func getMinimunWeight() -> Float {
            return 49.9
        }
    }
    class M_Kaku_Private11_1: ProfileAccount10_1{
        //足のサイズ(センチメートル)
        var myFootSize: Float = 27.0
        //イニシャライザ
        init(age:Int, weight: Float, foot:Float) {
            myFootSize = foot
            super.init(m_KakuAge: 43, m_KakuWeight: 59.1)
        }
        //意味はないけど、足のサイズに身長をかけてみた
        func calc() -> Float {
            return myFootSize * m_KakuHeight
        }
        //オーバーライド
        override func msgMyProfile(){
            //        print("オイラは\\(m_KakuAge)のおっさんだぞ")
            //        print("オイラの体重は\\(m_KakuWeight)だよ。運動せんと、、、💦")
            //スーパーさんを使う
            super.msgMyProfile()
            //ここに親クラスのメソッドを流用して追加
            print("足のサイズ(cm)は、\\(myFootSize)だよ。")
        }
    }
    var myFoot11_1: M_Kaku_Private11_1 = M_Kaku_Private11_1(age: 43, weight: 59.1, foot: 27.0)
    print("足のサイズ(cm)x 身長(m)は、\\(myFoot11_1.calc())")
    myFoot11_1.msgMyProfile()
    
    //拡張
    extension Float{
        var circleAround: Float{
            return self * 3.14159265359
        }
        var circleArea: Float{
            return self * self * 3.14159265359
        }
    }
    //実行
    let myCircle11_2: Float = 2
    print(myCircle11_2)
    print(myCircle11_2.circleAround)
    print(myCircle11_2.circleArea)
    """

    PointManageFile(追加分のみ)

    let pointEssentials11 = """
    ○継承:既存のクラスから新しいクラスを派生できるようにすることで、オブジェクト指向プログラミングにおけるオブジェクトの再利用の概念を拡張し、その後、それらの新しいクラスを拡張して新しい機能を追加
    👉継承により、そのクラスを新しいサブクラスの基礎として使用できるようになる。
    新しいサブクラスは親クラスのすべての機能を継承しますが、不足している機能を追加するために拡張できる。
    ○拡張:サブクラスを作成せずに既存のクラスに機能を追加する便利な代替オプションを提供。
    って書いてるとおり、元々あるクラスやSwift本来の機能なんかを
    再利用
    して、
    新たな独自の処理なんかを追加できるんだ
    👉元々(何かしら)ある機能(処理)に、何かを追加したいときに使うんだ!
    ってイメージしてもらえれば今は充分。
    """

    URLManageFile(追加分のみ)

    let urlEssentials11 = "https://note.com/m_kakudo/n/nb37c842877ec"

    以上。

    ま、クラスはやろうと思えばどこまでも果てしなく広くて奥も深いし、たくさんサンプルコードも転がってると思うから、

    自分で色々動かして、遊んで見てね〜〜〜!

    プログラミングでは、
    💃遊びながら動かすに優る近道なし🕺
    だからね

     
     
    タダの道楽者💫ネガティブなコメント一切お断り 裾野が広がりゃそれで良い 洋書と古典とSwiftをこよなく愛するオッさん👀 色即是空🕺 記事はマガジンの方が読みやすいかな💦 ちょい難とダラダラ💃 無駄な対立軸と課題探し思考は要らんな。 変幻自在➕縦横無尽➕融通無碍🟰天衣無縫

    あなたへのおすすめ