Day 24:让iOS也吃到SQL Delight

Keyword:SQLDelight,Native Driver

到24日,在iOS上呈现DB资料
KMMDay24


在昨天让Android可以享受到KMM底下的SQLDelight内容後,今天我们来让iOS也能使用SQLDelight.同样的,在iOS上使用需要比Android多一层的手续,才能让iOS也了解到Coroutine的使用方法.

我们现在来重写iOS(shared)内的NativeViewModel,之前是给网路api的Ktor使用,现在要在里面加入DB的使用,并且修改使用的方式.

//这是Kotlin 在iOSMain底下
class IOSNativeViewModel(
    private val onDataState: (List<CAFE>) -> Unit//这个callback由iOS端执行
) : KoinComponent {
    private val scope = IOSMainScope(Dispatchers.Main)
    private val dataRepository: DataRepository by inject()

    init {
        observeCafeList()
    }

    private fun observeCafeList() {
        scope.launch {
            dataRepository.getCafeFromDb().collect { dataState ->
                onDataState(dataState)//藉由callback让iOS也能接受Flow的数据
            }
        }
    }

    public fun fetchCafeListFromNewWork(cityName: String = "taipei") {
        scope.launch {
            val result = async { dataRepository.fetchCafesFromNetwork(cityName) }
            dataRepository.insertCafeToDB(result.await())
        }
    }

    fun onDestroy() {
        scope.onDestroy()
    }
}

然後我们修改原本的iOS专案内的ObserableViewModel,让这个物件的资料元从网路APi改为从DB上来的资料

这边我们是使用callback的方式,让flow在当数据改变时去执行特定的程序码,这边就很简单把的数据存入Published内,然後Published和ObservableObject就会去更新swiftUI的画面元件.记得加入onDestroy的函式,让画面在离开的时候销毁coroutine的scope,避免CoroutineLeak的情况发生

//这边是swift
import Foundation
import shared

class CafeEntityItemViewModel:ObservableObject{
    private var viewModel: IOSNativeViewModel? = nil
    @Published
    var cafes:[CAFE]? = nil
    func initData(){
        viewModel = IOSNativeViewModel{ [weak self] data in
            self?.cafes = data

        }
    }
    func onDestroy(){
        viewModel?.onDestroy()
        viewModel = nil
    }
    
}

最後在首页的ContentView修改为新的DB物件CAFE而不是原本的CafeResponseItem,并且让View再出现时开始拉取新网路资料,并且先显示DB资料,这样可以提高使用者体验.

//这是SwiftUI
import SwiftUI
import shared

struct ContentView: View {
    @ObservedObject var cafeEntityViewModel = CafeEntityItemViewModel()
    
    var cafes: [CAFE]?
    var body: some View{
        NavigationView {
            CafeListContent(cafelist: cafeEntityViewModel.cafes)
            .navigationBarTitle(Text("CafeList"), displayMode: .large)
            .onAppear(perform: {
                self.cafeEntityViewModel.initData()
            })
            .onDisappear(perform: {
                self.cafeEntityViewModel.onDestroy()
            })
        }
        
    }
}

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

struct CafeListContent: View{
    var cafelist: [CAFE]?
    var body : some View {
        ZStack{
            if let cafes = cafelist {
                List(cafes, id: \.id) { cafe in
                    CafeItemView(cafeItem: cafe)
                }
            }else{
                Text("Empty")
            }
        }
    }
}

struct CafeItemView : View {
    var cafeItem: CAFE

    var body: some View {
        HStack {
            VStack(alignment: .leading) {
                Text(cafeItem.name!).font(.headline)
                Text(cafeItem.id).font(.subheadline)
            }
        }
    }
}

明天开始会写KMM如何进行测试的


<<:  [Day 14] 表格图页面建立

>>:  Day14 NodeJS-NPM I

遵守政策的管理制度

-政策框架 最高管理层要求加强资讯安全并通过政策表达他们的保护要求。有效的资讯安全涉及人员、流程和...

【从实作学习ASP.NET Core】Day15 | 後台 | 自定义使用者栏位

延续昨天的会员功能,预设会员资讯栏位只有 Email 和 Password,今天要加上一些栏位让会员...

Ubersuggest 免费 SEO 工具教学,支援中文关键字分析与内容建议

经营自媒体网站最重要的就是要让文章被看见,有了流量才有信服力,而要曝光文章最快的方法除了购买付费广告...

予焦啦!装置树(DTB)解析

本节是以 Golang 上游 4b654c0eeca65ffc6588ffd9c99387a7e4...

[Day 15] backtesting 使用说明

策略(Strategy) 自定义策略 class SmaCrossCons(ConsStrategy...