朧の.Netの足跡
問合せ先:support@oborodukiyo.info サイト内検索はこちら
SwiftUI データの初期化を1回だけにしたい場合





SwiftUIで、データをそのまま持たせていると、表示される度に、初期化が何度も行われてしまいます。
それでは、困ってしまう場合があります。
そんな時はEnvironmentObjectを使います。
どう使うかというと、まず、初期化を一度だけにしたいデータ(配列だったり、普通のデータだったり)を持たせるクラスにObservableObjectプロトコルを継承させます。(サンプルコードではCityDataクラスです)
サンプルコードで保持したい実際のデータはCityDataクラスのメンバのmyDataフィールドである[TwitterData]の配列です。
そして、CityDataクラスを利用したいViewで(サンプルコードではMyDetailView)、CityData型のメンバを宣言する時に、@EnvironmentObject属性を付けます。
最後にSaigaiInfoAppクラスのbody内で、ContentView()に.enviromentObject(CityData())をModifierします。
このサンプルコードでは、初期ViewはContentViewで(都道府県名のリストを表示するView)、そこでListの一つの都道府県名をクリックすると、MyDetailViewが(市区町村名のリストを表示するView)呼び出されます。


SaigaiInfoApp.swift

import SwiftUI

@main
struct SaigaiInfoApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(CityData())
                /*複数保持したいデータがある場合は次のように続けます。
                .environmentObject(HogeClass())
                .environmentObject(HogehogeClass())
                */
        }
    }
}
    

ContentView.swift

import SwiftUI

class TwitterData: Identifiable {
    //都道府県名
    var prefecture: String = ""
    //市区町村名
    var city: String = ""
    var twitter: String = ""
    var note: String = ""
}

class Prefecture: ObservableObject {
    @Published var myData = [TwitterData]()
    @State var loaded: Bool = false
    
    init() {
        if self.loaded {
            return
        }
        
        if let path: String = Bundle.main.path(forResource: "saigai-prefList", ofType: "csv") {
            let enc = String.Encoding.utf8
            do {
                let s = try String(contentsOfFile: path, encoding: enc)
                let rawData = s.split(separator: "\r\n")
                
                for d in rawData {
                    
                    if String(d) == "都道府県" {
                        //何もしない
                    } else {
                        print(d)
                        let s = TwitterData()
                        s.prefecture = String(d)
                        myData.append(s)
                    }
                }
                self.loaded = true
            } catch {
                print("ファイルの内容の取得に失敗しました。")
            }
        }
        
    }
}

struct ContentView: View {
    @ObservedObject var prefectureList = Prefecture()
    
    init() {
        
    }
    
    var body: some View {
        NavigationView {
            VStack {
                List(self.prefectureList.myData) {
                    item in
                        NavigationLink(destination: MyDetailView(item.prefecture)) {
                            
                        Text(item.prefecture)
                            .font(.subheadline)
                        Spacer(minLength: 5).fixedSize()
                        }
                }
            }
        }.navigationViewStyle(StackNavigationViewStyle())
    }
    
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
    

CityData.swift

import Foundation

class CityData: ObservableObject {
    @Published var myData = [TwitterData]()
    
    init() {
        
        if let path: String = Bundle.main.path(forResource: "saigai-twitterList", ofType: "csv") {
            let enc = String.Encoding.utf8
            do {
                let s = try String(contentsOfFile: path, encoding: enc)
                let rawData = s.split(separator: "\r\n")
                var blnFirst: Bool = true
                for d in rawData {
                    
                    if blnFirst {
                        blnFirst = false
                    } else {
                        print(d)
                        let data = d.split(separator: ",")
                        let twitter: TwitterData = TwitterData()
                        twitter.prefecture = String(data[1])
                        twitter.city = String(data[2])
                        twitter.twitter = String(data[3])
                        if data.count == 5 {
                            twitter.note = String(data[4])
                        }
                        self.myData.append(twitter)
                    }
                }
                
            } catch {
                print("ファイルの内容の取得に失敗しました。")
            }
        }

    }
    
    func getData(_ item: String) -> [TwitterData] {
        var data = [TwitterData]()
        
        for d in self.myData {
            if d.prefecture == item {
                data.append(d)
            }
        }
        
        return data
    }
}

    

DetailView.swift

import SwiftUI

struct MyDetailView : View {
    
    @EnvironmentObject var TwitterList: CityData
    
    var pref: String
    
    init(_ d: String) {
        pref = d
    }
    
    var body: some View {
        VStack{
            Text("タップ1回でTwitterが、2回で役所のホームページが開きます")
            Divider()
            Text(self.pref).font(.title)
            List(TwitterList.getData(self.pref)) {
            item in
            HStack {
                Text(item.city)
                VStack {
                    Text("Twitter:" + item.twitter)
                    Text(item.note)
                }.gesture(TapGesture(count:2)
                            .onEnded{ (val) in
                                if item.note.contains("http") {
                                    let text: String = item.note
                                    debugPrint(text)
                                    let url = URL(string: text)
                                    if UIApplication.shared.canOpenURL(url!) {
                                        UIApplication.shared.open(url!, options:[:], completionHandler: nil)
                                    }
                                }

                            })
                
                .gesture(TapGesture(count: 1)
                            .onEnded{ val in
                                if item.twitter.contains("@") {
                                    let text: String = "https://twitter.com/" + item.twitter.suffix(item.twitter.count - 1)
                                    let url = URL(string: text)
                                    if UIApplication.shared.canOpenURL(url!) {
                                        UIApplication.shared.open(url!, options:[:], completionHandler: nil)
                                    }
                                }

                            })
            }.font(.subheadline)
        }
        }
    }
}

struct MyDetailView_Previews: PreviewProvider {
    static var previews: some View {
        MyDetailView("北海道")
    }
}

    









良いやや良い普通やや悪い悪い

投稿日時評価コメント