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

【じっくりSw1ftUI41】実践編11〜第24章 Swift 構造化同時実行の概要①〜同時実行処理とは?

    さてと、前回

    はこれまでに学んだ

    プロパティラッパーを駆使したViewの作りかた

    をやったので、今回は、

    スレッド使いかたに入ってく〜〜〜

    オイラの学びなんざ関係ない、いらないって人は

    で公開されてっから、好きにやればいいんじゃね👀
    って感じで早速本編へ〜〜〜〜🕺

    じっくり第24章を読んでく👓

    概要

    マルチタスクを実行する際に同時実行まで含めた方法
    をこれから書いてくぜ👍

    って言ってんね👀

    第1〜4節

    同時実行するまでのCPUのプロセスの流れに触れながら、

    キーワードは スレッド(Threads)てゆーてんね👀

    Mainスレッドだけでは時間がかかる場合に、同時実行処理で、時間を短縮できるし、レンダリングであったり、イベントであったり、ユーザーインタラクションであったりで効果を発揮できるようにハンドリングしようぜ

    みたいなことが書いてあって、で初めて

    同期コード処理(asynchronous code execution)

    が出てきたね👀そいで、

    Swift5.5からはそーいったスレッド処理の構築もめっちゃ簡単になったから、実際にコードを見ながら体感してこう

    とまあ、英語力がそんなにない(技術書が辞書なしでスラスラ読める程度のオッサン😭)が掻い摘んで記事用にここまでを要約するとこんな感じ💦
    ま、

    スレッドで何か処理をしてる裏側でもMainプロセスはちゃ〜〜んと動いてるんだぜ

    とかそれ以外でも、スレッドとか同期処理をやったことがない人向けの解説もきちんと書いておる👓(ふむふむって感じで読んでみてね〜〜〜)

    んで第5章以降で実際のコードを動かしながら学んでく

    まずはサンプルコードがてら雛形

    import SwiftUI
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                actSome()
            }){
                Text("果物屋さんの同期処理")
            }
        }
        func actSome(){
            
        }
        func actLong(){
            
        }
    }
    
    #Preview {
        Essentials24()
    }

    で、非同期処理から実行してこうらしいので〜〜〜

    import SwiftUI
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                actSome()
            }){
                Text("果物屋さんの同期処理")
            }
        }
        func actSome(){
            print("開始")
            print("開始時刻\(Date())")
            actLong()
            print("終了時刻\(Date())")
            print("終了")
        }
        func actLong(){
            sleep(30)
            print("同期処理完了\(Date())")
        }
    }
    
    #Preview {
        Essentials24()
    }

    実行すると、、、

    画像
    てな感じで30秒待機してから
    順列で処理が流れてんね👀

    同期処理をやるために、、、

    本のサンプルコードに倣って

    asyncキーワードを追加

    import SwiftUI
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                actSome()
            }){
                Text("果物屋さんの同期処理")
            }
        }
        func actSome() async{
            print("開始")
            print("開始時刻\(Date())")
            actLong()
            print("終了時刻\(Date())")
            print("終了")
        }
        func actLong() async{
            sleep(30)
            print("同期処理完了\(Date())")
        }
    }
    
    #Preview {
        Essentials24()
    }

    すっと、、、

    画像
    てな感じで await を入れろし💢

    って感じの赤の警告エラーが出てくんね💦で、警告どおりにFixすっと、、、

    画像
    コードエラーは解消されんのに、
    アプリケーションエラーでダメやん😭
    なあぜなあぜ🧐❓

    で、読み進めると、、、実は

    import SwiftUI
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                actSome()
            }){
                Text("果物屋さんの同期処理")
            }
        }
        func actSome() {
            Task{
                print("開始")
                print("開始時刻\(Date())")
                await actLong()
                print("終了時刻\(Date())")
                print("終了")
            }
        }
        func actLong() async{
            sleep(30)
            print("同期処理完了\(Date())")
        }
    }
    
    #Preview {
        Essentials24()
    }

    てな感じで、

    • 同期処理元(ここだとactSome()):Taskでasyncする側からのレスをawaitで返ってくるのを待つ

    • 同期処理先(ここだとactLong()):asyncされたからawaitされてるところに返す

    ってイメージかな👀VBAなんかの引数の渡しと戻しみたいなもんなのかねえ🧐ま、実際さっきのエラーも解消されて

    画像

    ボタンを押すと、、、

    画像
    てな感じで実行できた

    ただし、ここから先がプロットと食い違うと色々ややこしくなりそうなので、本編に合わせて〜〜〜

    import SwiftUI
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                main()
            }){
                Text("果物屋さんの同期処理")
            }
        }
        
        func main(){
            Task{
                actSome()
            }
        }
        func actSome() {
            Task{
                print("開始")
                print("開始時刻\(Date())")
                await actLong()
                print("終了時刻\(Date())")
                print("終了")
            }
        }
            
        func actLong() async{
            sleep(30)
            print("同期処理完了\(Date())")
        }
    }
    
    #Preview {
        Essentials24()
    }

    てな感じで

    画像
    動きはしてるみたいだけど、、、

    関数がいくつもあるのは正直めんどくさいし、美しくないね🧐

    なので、本編でも〜〜〜

    import SwiftUI
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                Task{
                    actSome()
                }
            }){
                Text("果物屋さんの同期処理")
            }
        }
    
        func actSome() {
            Task{
                print("開始")
                print("開始時刻\(Date())")
                await actLong()
                print("終了時刻\(Date())")
                print("終了")
            }
        }
            
        func actLong() async{
            sleep(30)
            print("同期処理完了\(Date())")
        }
    }
    
    #Preview {
        Essentials24()
    }

    って感じで〜〜〜

    画像
    実行できてんね👀

    ここでポイント①ここまでのコードを見ていてお気づきの人もいるとは思うんだが、、、

    この章のこれまでのコードも実は、
    教科書どおりに打って見ても実はエラーになる箇所が2箇所あるので、動くようにサンプルコードを変えてます🤣
    ここも多分、async入れる箇所と、await入れる箇所を検証もせずに頭でコードだけ売ってるからこんなことになる藁🤣

    1. 必ずサンプルコードだけを読んで理解した気にならずに、

    2. 早い段階で必ずサンプルコードが正常に動くかを実際に動かしてみて検証し、

    3. 動かないなら、なんで動かないかを調べよう🕺

    👉練習とか自己学習の段階でならいくらでも失敗していいんだけど、理論とかコードの作りからだけで理解した気になって、いざリリースした後で発覚してスレッド処理のコードを全部書き換えとか恐ろしくて仕方なくなるからね🧐お客さんに余計な費用かけるし、リリースできなくなると商機を逸するし〜〜〜

    さてと、同期バインディング

    戻り値の型を決めて〜〜〜

    import SwiftUI
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                Task{
                    actSome()
                }
            }){
                Text("果物屋さんの同期処理")
            }
        }
    
        func actSome() {
            Task{
                print("開始")
                print("開始時刻\(Date())")
                print("----------------------")
                async let result = actLong()
                print("終了時刻\(await result))")
                print("終了")
            }
        }
            
        func actLong() async -> Date{
            sleep(3)
            return Date()
        }
    }
    
    #Preview {
        Essentials24()
    }

    (待機時間が30秒は長いので3に変更した🤣)てな感じですると〜〜〜

    画像
    てな感じでもできるし〜〜

    別に教科書どおりにしなくても、同期処理をさせたいだけであれば、

    import SwiftUI
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                Task{
                    await actSome()
                }
            }){
                Text("果物屋さんの同期処理")
            }
        }
    
        func actSome() async{
            Task{
                print("開始")
                print("開始時刻\(Date())")
                print("----------------------")
                async let result = actLong()
                print("終了時刻\(await result))")
                print("終了")
            }
        }
            
        func actLong() async -> Date{
            sleep(3)
            return Date()
        }
    }
    
    #Preview {
        Essentials24()
    }

    てな感じでも

    画像
    同期自体はできてる〜〜〜

    ま、最初は教科書どおりに入って、自分がしたい通りにカスタマイズは可能ってことで🕺好きな方を使ってくだされ

    エラーハンドリング

    ここは、今までどおりの感覚で〜〜〜

    import SwiftUI
    
    enum Essentials24ErrorHandringEnum: Error {
        case longTime
        case shortTime
    }
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                Task{
                    await actSome()
                }
            }){
                Text("果物屋さんの同期処理")
            }
        }
    
        func actSome() async{
            Task{
                print("開始")
                print("開始時刻\(Date())")
                print("----------------------")
                async let result = actLong()
                async let times = timeSpan(delay: 20)
                print("かかった時間\(await times)")
                print("終了時刻\(await result))")
                print("終了")
            }
        }
            
        func actLong() async -> Date{
            sleep(3)
            return Date()
        }
        
        func timeSpan(delay: UInt32) async throws{
            if delay < 3 {
                throw Essentials24ErrorHandringEnum.shortTime
            } else if delay > 20 {
                throw Essentials24ErrorHandringEnum.longTime
            }
            sleep(delay)
            print("処理完了\(Date())")
        }
    }
    
    #Preview {
        Essentials24()
    }

    って感じで列挙体を作ってあげると、

    画像
    てな感じでエラー

    ま、なぜかと言えば、

    エラーハンドリング=エラー処理でやることなのに、、、

    tryがないから

    なので、

    import SwiftUI
    
    enum Essentials24ErrorHandringEnum: Error {
        case longTime
        case shortTime
    }
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                Task{
                    await actSome()
                }
            }){
                Text("果物屋さんの同期処理")
            }
        }
    
        func actSome() async{
            Task{
                print("開始")
                print("開始時刻\(Date())")
                print("----------------------")
                async let result = actLong()
                print("終了時刻\(await result))")
                print("終了")
                do{
                    try await timeSpan(delay: 5)
                } catch Essentials24ErrorHandringEnum.shortTime {
                    print("時間短すぎ")
                } catch Essentials24ErrorHandringEnum.longTime {
                    print("時間かかり過ぎ")
                } catch {
                    print("意味不明なエラー")
                }
            }
        }
            
        func actLong() async -> Date{
            sleep(3)
            return Date()
        }
        
        func timeSpan(delay: UInt32) async throws{
            if delay < 3 {
                throw Essentials24ErrorHandringEnum.shortTime
            } else if delay > 20 {
                throw Essentials24ErrorHandringEnum.longTime
            }
            sleep(delay)
            print("かかった時間\(Date())")
        }
    }
    
    #Preview {
        Essentials24()
    }
    

    てな感じに変更してあげて実行すると、、、

    画像
    てな感じになるんだけど、

    ここでポイント②エラーハンドリングは実際の現場では、

    ビューのボタンなんかがちゃんと反応したか

    なんかを返すときに、こーゆー処理は入れるので、

    import SwiftUI
    
    enum Essentials24ErrorHandringEnum: Error {
        case longTime
        case shortTime
    }
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                Task{
                    do{
                        try await timeSpan(delay: 1)
                    } catch Essentials24ErrorHandringEnum.shortTime {
                        print("時間短すぎ")
                    } catch Essentials24ErrorHandringEnum.longTime {
                        print("時間かかり過ぎ")
                    } catch {
                        print("意味不明なエラー")
                    }
                    await actSome()
                }
            }){
                Text("果物屋さんの同期処理")
            }
        }
    
        func actSome() async{
            Task{
                print("開始")
                print("開始時刻\(Date())")
                print("----------------------")
                async let result = actLong()
                print("終了時刻\(await result))")
                print("終了")
            }
        }
            
        func actLong() async -> Date{
            sleep(3)
            return Date()
        }
        
        func timeSpan(delay: UInt32) async throws{
            print("タップされました\(Date())")
            if delay < 1 {
                throw Essentials24ErrorHandringEnum.shortTime
            } else if delay > 1 {
                throw Essentials24ErrorHandringEnum.longTime
            }
            sleep(delay)
            print("タップ完了\(Date())")
        }
    }
    
    #Preview {
        Essentials24()
    }

    てお遊びで作ると、

    画像
    よりイメージが湧きやすいかな🧐
    これでもしエラーな時だけ、エラーが返るってイメージで

    ここでポイント③do-catch文については、

    忘れていた人も多いと思うので、リンク先の記事で見返してね〜〜〜🕺

    この記事で書いていた時は、

    Playground=あくまでもSwiftってプログラミング言語のSyntax:文法

    でやってただけで、SwiftUIフレームワークでの実践では初めてやるのに、最初はエラーが出まくって当たり前だからね〜〜〜

    SwiftUIフレームワークで動かしながら、
    SwiftUI用のコードの書き方を学ぶ
    👉実践編

    なので、、、

    一回で出来ない、一回しか習ってないのに忘れる
    =当たり前
    (てか別に最終的に使いこなせればいいだけ
    👉一回で覚える必要なんてない
    =お受験勉強ではないからね)

    覚える🔛忘れる
    コードを書く🔛エラーが出る

    を繰り返して、ゆくゆくは

    いつの間にか何も意識せずに自分の作りたいアプリが作れる
    =至高のフロー

    状態になればいいだけだから。

    気にしない気にしない。

    エラーが出まくっても、なんでエラーが出たのかを最初のうちは理解すればいいだけ。

    逆に典型的な理系出身者とかで記憶するのが当たり前、全部知っていて当たり前みたいな人も過去の現場でゆーてる人を見たことあるけど、

    丸暗記したところで、自分のアプリでは一生使わないか進化し続けるプログラミング言語でまた別のフレームワークが主流になれば、どうせ変更されるんだから=効率が悪すぎる

    し、そんな人ほど、変化に対応できなくなって、

    COBOLの時代なんかの感覚で完璧に理解しようとか覚えようとして失敗してるからね〜〜〜

    成れの果ては、

    なんかでも書いてるとおり🕺
    ま、今や客先常駐の派遣技術者に頼りまくって、難易度とかを理解してないまま、予算の関係なんかで簡単に使い捨ててきた結果、個人で趣味でやってる人よりも受け入れ先の企業の方が

    最新の言語に関する知識や技能=本来の情報資産
    がない人材しか揃っていない

    なんて逆転現象が起きてるからね〜〜〜〜🧐
    (それでいいのか?ってのはあるけど、アプリを作りたいってだけなオイラとかみんなには関係ない話。それはその企業が今後どーするかだけだからね。)

    と、ここまでで盛りだくさんになってきてる

    のと、次節からはTaskの理解なんかに入っていくのでちょっと毛色が違うし、

    この記事は一旦ここまででストップさせておこう👀💦
    続きは明日書こう!
    今日は、ゆっくりここまでの復習でもしておいてもらえると幸い〜〜〜🕺

    今回のコード(まとめ)

    import SwiftUI
    
    enum Essentials24ErrorHandringEnum: Error {
        case longTime
        case shortTime
    }
    
    struct Essentials24: View {
        var body: some View {
            Button(action: {
                Task{
                    do{
                        try await timeSpan(delay: 1)
                    } catch Essentials24ErrorHandringEnum.shortTime {
                        print("時間短すぎ")
                    } catch Essentials24ErrorHandringEnum.longTime {
                        print("時間かかり過ぎ")
                    } catch {
                        print("意味不明なエラー")
                    }
                    await actSome()
                }
            }){
                Text("果物屋さんの同期処理")
            }
        }
    
        func actSome() async{
            Task{
                print("開始")
                print("開始時刻\(Date())")
                print("----------------------")
                async let result = actLong()
                print("終了時刻\(await result))")
                print("終了")
            }
        }
            
        func actLong() async -> Date{
            sleep(3)
            return Date()
        }
        
        func timeSpan(delay: UInt32) async throws{
            print("タップされました\(Date())")
            if delay < 1 {
                throw Essentials24ErrorHandringEnum.shortTime
            } else if delay > 1 {
                throw Essentials24ErrorHandringEnum.longTime
            }
            sleep(delay)
            print("タップ完了\(Date())")
        }
    }
    
    #Preview {
        Essentials24()
    }

    たったこれだけで結構、紙面が行くもんですなあ🧐

    Apple公式

    さてと次回は、

    💃後半戦のTaskの理解からやってく〜〜〜🕺
    Threadsは結構、高度なアプリ開発では使う処理だから、
    今回と次回でこんなやり方があるんだ!で触れてもらえれば十分

    記事公開後、

    いつもどおり、

    でやった操作を〜〜〜

    画像
    ボタンをタップ〜〜
    画像
    タップしてもデバッグエリアにちゃんと出た🕺
    画像
    てな
    画像
    てな
    画像
    感じ

    サンプルコード

    ◾️Essentials24.swift

    import SwiftUI
    import WebKit
    
    //タイトル
    let essentialsChapter24NavigationTitle = "第24章"
    let essentialsChapter24Title = "第24章 Swift 構造化同時実行の概要"
    let essentialsChapter24_1SubTitle = "第1節 基本(Task、async、await)〜エラーハンドリングまで"
    
    //コード
    let codeEssentials24_1 = """
    struct Essentials24_1ContentsView: View {
        var body: some View {
            Button(action: {
                Task{
                    do{
                        try await timeSpan(delay: 1)
                    } catch Essentials24ErrorHandringEnum.shortTime {
                        print("時間短すぎ")
                    } catch Essentials24ErrorHandringEnum.longTime {
                        print("時間かかり過ぎ")
                    } catch {
                        print("意味不明なエラー")
                    }
                    await actSome()
                }
            }){
                Text("果物屋さんの同期処理")
            }
        }
    
        func actSome() async{
            Task{
                print("開始")
                print("開始時刻\(Date())")
                print("----------------------")
                async let result = actLong()
                print("終了時刻\\(await result))")
                print("終了")
            }
        }
            
        func actLong() async -> Date{
            sleep(3)
            return Date()
        }
        
        func timeSpan(delay: UInt32) async throws{
            print("タップされました\(Date())")
            if delay < 1 {
                throw Essentials24ErrorHandringEnum.shortTime
            } else if delay > 1 {
                throw Essentials24ErrorHandringEnum.longTime
            }
            sleep(delay)
            print("タップ完了\(Date())")
        }
    }
    """
    
    //ポイント
    let pointEssentials24_1 = """
    ◾️ここでポイント①
     ここまでのコードを見ていてお気づきの人もいるとは思うんだが、、、この章のこれまでのコードも実は、教科書どおりに打って見ても実はエラーになる箇所が2箇所あるので、動くようにサンプルコードを変えてます🤣
     ここも多分、async入れる箇所と、await入れる箇所を検証もせずに頭でコードだけ売ってるからこんなことになる藁🤣
    
     ①必ずサンプルコードだけを読んで理解した気にならずに、
     ②早い段階で必ずサンプルコードが正常に動くかを実際に動かしてみて検証し、
     ③動かないなら、なんで動かないかを調べよう🕺
     👉練習とか自己学習の段階でならいくらでも失敗していいんだけど、理論とかコードの作りからだけで理解した気になって、いざリリースした後で発覚してスレッド処理のコードを全部書き換えとか恐ろしくて仕方なくなるからね🧐お客さんに余計な費用かけるし、リリースできなくなると商機を逸するし〜〜〜
    
    ◾️ここでポイント②
     エラーハンドリングは実際の現場では、
     ビューのボタンなんかがちゃんと反応したかなんかを返すときに、こーゆー処理は入れる
    
    ◾️ここでポイント③
     do-catch文については、忘れていた人も多いと思うので、リンク先の記事で見返してね〜〜〜🕺
     この記事で書いていた時は、Playground=あくまでもSwiftってプログラミング言語のSyntax:文法でやってただけで、SwiftUIフレームワークでの実践では初めてやるのに、最初はエラーが出まくって当たり前だからね〜〜〜
     SwiftUIフレームワークで動かしながら、SwiftUI用のコードの書き方を学ぶ👉実践編なので、、、
     一回で出来ない、一回しか習ってないのに忘れる=当たり前(てか別に最終的に使いこなせればいいだけ👉一回で覚える必要なんてない=お受験勉強ではないからね)
     覚える🔛忘れる、コードを書く🔛エラーが出るを繰り返して、ゆくゆくは
     いつの間にか何も意識せずに自分の作りたいアプリが作れる=至高のフロー
     状態になればいいだけだから。
     気にしない気にしない。
     エラーが出まくっても、なんでエラーが出たのかを最初のうちは理解すればいいだけ。
     逆に典型的な理系出身者とかで記憶するのが当たり前、全部知っていて当たり前みたいな人も過去の現場でゆーてる人を見たことあるけど、丸暗記したところで、自分のアプリでは一生使わないか進化し続けるプログラミング言語でまた別のフレームワークが主流になれば、どうせ変更されるんだから=効率が悪すぎるし、そんな人ほど、変化に対応できなくなって、COBOLの時代なんかの感覚で完璧に理解しようとか覚えようとして失敗してるからね〜〜〜
     成れの果ては、他の記事なんかでも書いてるとおり🕺
     ま、今や客先常駐の派遣技術者に頼りまくって、難易度とかを理解してないまま、予算の関係なんかで簡単に使い捨ててきた結果、個人で趣味でやってる人よりも受け入れ先の企業の方が最新の言語に関する知識や技能=本来の情報資産がない人材しか揃っていないなんて逆転現象が起きてるからね〜〜〜〜🧐
     (それでいいのか?ってのはあるけど、アプリを作りたいってだけなオイラとかみんなには関係ない話。それはその企業が今後どーするかだけだからね。)
    """
    //URL
    let urlEssentials24_1 = "https://note.com/m_kakudo/n/n864d914b9b54"
    
    //ビュー管理構造体
    struct ListiOSApp17DevelopmentEssentialsCh24: Identifiable {
        var id: Int
        var title: String
        var view: ViewEnumiOSApp17DevelopmentEssentialsCh24
    }
    //遷移先の画面を格納する列挙型
    enum ViewEnumiOSApp17DevelopmentEssentialsCh24{
        case Sec1
    }
    //各項目に表示するリスト項目
    let dataiOSApp17DevelopmentEssentialsCh24: [ListiOSApp17DevelopmentEssentialsCh24] = [
        ListiOSApp17DevelopmentEssentialsCh24(id: 1, title: essentialsChapter24_1SubTitle, view: .Sec1),
    ]
    struct iOSApp17DevelopmentEssentialsCh24: View {
        var body: some View {
            VStack {
                Divider()
                List (dataiOSApp17DevelopmentEssentialsCh24) { data in
                    self.containedViewiOSApp17DevelopmentEssentialsCh24(dataiOSApp17DevelopmentEssentialsCh24: data)
                }
                .edgesIgnoringSafeArea([.bottom])
            }
            .navigationTitle(essentialsChapter24NavigationTitle)
            .navigationBarTitleDisplayMode(.inline)
        }
        //タップ後に遷移先へ遷移させる関数
        func containedViewiOSApp17DevelopmentEssentialsCh24(dataiOSApp17DevelopmentEssentialsCh24: ListiOSApp17DevelopmentEssentialsCh24) -> AnyView {
            switch dataiOSApp17DevelopmentEssentialsCh24.view {
            case .Sec1:
                return AnyView(NavigationLink (destination: Essentials24_1()) {
                    Text(dataiOSApp17DevelopmentEssentialsCh24.title)
                })
            }
        }
    }
    #Preview {
        iOSApp17DevelopmentEssentialsCh24()
    }
    
    enum Essentials24ErrorHandringEnum: Error {
        case longTime
        case shortTime
    }
    
    struct Essentials24_1: View {
        var body: some View {
            VStack{
                TabView {
                    Essentials24_1ContentsView()
                        .tabItem {
                            Image(systemName: contentsImageTab)
                            Text(contentsTextTab)
                        }
                    Essentials24_1Code()
                        .tabItem {
                            Image(systemName: codeImageTab)
                            Text(codeTextTab)
                        }
                    Essentials24_1Points()
                        .tabItem {
                            Image(systemName: pointImageTab)
                            Text(pointTextTab)
                        }
                    Essentials24_1WEB()
                        .tabItem {
                            Image(systemName: webImageTab)
                            Text(webTextTab)
                        }
                }
            }
        }
    }
    #Preview {
        Essentials24_1()
    }
    
    struct Essentials24_1Code: View {
        var body: some View {
            ScrollView{
                Text(codeEssentials24_1)
            }
        }
    }
    #Preview {
        Essentials24_1Code()
    }
    struct Essentials24_1Points: View {
        var body: some View {
            ScrollView{
                Text(pointEssentials24_1)
            }
        }
    }
    #Preview {
        Essentials24_1Points()
    }
    struct Essentials24_1WebView: 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 Essentials24_1WEB: View {
        private var url:URL = URL(string: urlEssentials24_1)!
        var body: some View {Essentials24_1WebView(searchURL: url)
        }
    }
    #Preview {
        Essentials24_1WEB()
    }
    
    struct Essentials24_1ContentsView: View {
        var body: some View {
            Button(action: {
                Task{
                    do{
                        try await timeSpan(delay: 1)
                    } catch Essentials24ErrorHandringEnum.shortTime {
                        print("時間短すぎ")
                    } catch Essentials24ErrorHandringEnum.longTime {
                        print("時間かかり過ぎ")
                    } catch {
                        print("意味不明なエラー")
                    }
                    await actSome()
                }
            }){
                Text("果物屋さんの同期処理")
            }
        }
    
        func actSome() async{
            Task{
                print("開始")
                print("開始時刻\(Date())")
                print("----------------------")
                async let result = actLong()
                print("終了時刻\(await result))")
                print("終了")
            }
        }
            
        func actLong() async -> Date{
            sleep(3)
            return Date()
        }
        
        func timeSpan(delay: UInt32) async throws{
            print("タップされました\(Date())")
            if delay < 1 {
                throw Essentials24ErrorHandringEnum.shortTime
            } else if delay > 1 {
                throw Essentials24ErrorHandringEnum.longTime
            }
            sleep(delay)
            print("タップ完了\(Date())")
        }
    }
    
    #Preview {
        Essentials24_1ContentsView()
    }

    ◾️EssentialsMenu.swift

    //フレームワーク
    import SwiftUI
    import WebKit
    
    //ビュー管理構造体
    struct ListiOSApp17DevelopmentEssentials: Identifiable {
        var id: Int
        var title: String
        var view: ViewEnumiOSApp17DevelopmentEssentials
    }
    //遷移先の画面を格納する列挙型
    enum ViewEnumiOSApp17DevelopmentEssentials {
        case Ch1
        //じっくり13で追加
        case Ch2
        //じっくり14で追加
        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
        //じっくり25で追加
        case Ch12
        //じっくり26で追加
        case Ch13
        //じっくり27,28で追加
        case Ch14
        //じっくり29で追加
        case Ch15
        //じっくり31で追加
        case Ch16
        //じっくり32で追加
        case Ch17
        //じっくり33で追加
        case Ch18
        //じっくり34で追加
        case Ch19
        //じっくり35で追加
        case Ch20
        //じっくり36で追加
        case Ch21
        //じっくり37で追加
        case Ch22
        //じっくり40で追加
        case Ch23
        //じっくり41で追加
        case Ch24
    }
    //各項目に表示する文字列
    let dataiOSApp17DevelopmentEssentials: [ListiOSApp17DevelopmentEssentials] = [
        ListiOSApp17DevelopmentEssentials(id: 1, title: essentialsChapter1Title, view: .Ch1),
        //じっくり13で追加
        ListiOSApp17DevelopmentEssentials(id: 2, title: essentialsChapter2Title, view: .Ch2),
        //じっくり13で追加
        ListiOSApp17DevelopmentEssentials(id: 3, title: essentialsChapter3Title, view: .Ch3),
        //じっくり15で追加
        ListiOSApp17DevelopmentEssentials(id: 4, title: essentialsChapter4Title, view: .Ch4),
        //じっくり16で追加
        ListiOSApp17DevelopmentEssentials(id: 5, title: essentialsChapter5Title, view: .Ch5),
        //じっくり17で追加
        ListiOSApp17DevelopmentEssentials(id: 6, title: essentialsChapter6Title, view: .Ch6),
        //じっくり18で追加
        ListiOSApp17DevelopmentEssentials(id: 7, title: essentialsChapter7Title, view: .Ch7),
        //じっくり19で追加
        ListiOSApp17DevelopmentEssentials(id: 8, title: essentialsChapter8Title, view: .Ch8),
        //じっくり20、21で追加
        ListiOSApp17DevelopmentEssentials(id: 9, title: essentialsChapter9Title, view: .Ch9),
        //じっくり22、23で追加
        ListiOSApp17DevelopmentEssentials(id: 10, title: essentialsChapter10Title, view: .Ch10),
        //じっくり24で追加
        ListiOSApp17DevelopmentEssentials(id: 11, title: essentialsChapter11Title, view: .Ch11),
        //じっくり25で追加
        ListiOSApp17DevelopmentEssentials(id: 12, title: essentialsChapter12Title, view: .Ch12),
        //じっくり26で追加
        ListiOSApp17DevelopmentEssentials(id: 13, title: essentialsChapter13Title, view: .Ch13),
        //じっくり27,28で追加
        ListiOSApp17DevelopmentEssentials(id: 14, title: essentialsChapter14Title, view: .Ch14),
        //じっくり29で追加
        ListiOSApp17DevelopmentEssentials(id: 15, title: essentialsChapter15Title, view: .Ch15),
        //じっくり31で追加
        ListiOSApp17DevelopmentEssentials(id: 16, title: essentialsChapter16Title, view: .Ch16),
        //じっくり32で追加
        ListiOSApp17DevelopmentEssentials(id: 17, title: essentialsChapter17Title, view: .Ch17),
        //じっくり33で追加
        ListiOSApp17DevelopmentEssentials(id: 18, title: essentialsChapter18Title, view: .Ch18),
        //じっくり34で追加
        ListiOSApp17DevelopmentEssentials(id: 19, title: essentialsChapter19Title, view: .Ch19),
        //じっくり35で追加
        ListiOSApp17DevelopmentEssentials(id: 20, title: essentialsChapter20Title, view: .Ch20),
        //じっくり36で追加
        ListiOSApp17DevelopmentEssentials(id: 21, title: essentialsChapter21Title, view: .Ch21),
        //じっくり37で追加
        ListiOSApp17DevelopmentEssentials(id: 22, title: essentialsChapter22Title, view: .Ch22),
        //じっくり40で追加
        ListiOSApp17DevelopmentEssentials(id: 23, title: essentialsChapter23Title, view: .Ch23),
        //じっくり41で追加
        ListiOSApp17DevelopmentEssentials(id: 24, title: essentialsChapter24Title, view: .Ch24),
    ]
    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)
                })
                //じっくり24で追加
            case .Ch11:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh11()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり25で追加
            case .Ch12:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh12()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり26で追加
            case .Ch13:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh13()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり27,28で追加
            case .Ch14:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh14()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり29で追加
            case .Ch15:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh15()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり31で追加
            case .Ch16:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh16()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり32で追加
            case .Ch17:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh17()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり33で追加
            case .Ch18:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh18()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり34で追加
            case .Ch19:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh19()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり35で追加
            case .Ch20:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh20()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり36で追加
            case .Ch21:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh21()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり37で追加
            case .Ch22:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh22()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり40で追加
            case .Ch23:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh23()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
                //じっくり41で追加
            case .Ch24:
                return AnyView(NavigationLink (destination: iOSApp17DevelopmentEssentialsCh24()) {
                    Text(dataiOSApp17DevelopmentEssentials.title)
                })
            }
        }
    }
    
    #Preview {
        iOSApp17DevelopmentEssentials()
    }

    以上🕺

    GWも何だかんだで適度にPC触りながらで良いリズム〜〜〜
    みなさんも良き残り2.5連休を〜〜〜

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

    あなたへのおすすめ