Ios 如何在SwiftUI中实现自定义委托

Ios 如何在SwiftUI中实现自定义委托,ios,delegates,swiftui,delegation,Ios,Delegates,Swiftui,Delegation,例如,我有一个SwitUI ContentView。当你第一次做这个项目的时候 import SwiftUI struct ContentView: View { var manager = TestManager() var body: some View { ZStack{ Color(.green) .edgesIgnoringSafeArea(.all) VStack { Text("T

例如,我有一个SwitUI ContentView。当你第一次做这个项目的时候

import SwiftUI

struct ContentView: View {
   var manager = TestManager()
   var body: some View {
    ZStack{
        Color(.green)
            .edgesIgnoringSafeArea(.all)
        VStack {
            Text("Test Text")

            Button(action:{}) {
                Text("Get number 2")
                    .font(.title)
                    .foregroundColor(.white)
                .padding()
                .overlay(RoundedRectangle(cornerRadius: 30)
                .stroke(Color.white, lineWidth: 5))
                }
           }
       }
   }
}
我有一个TestManager来处理Api调用。我为有两个函数的类创建了一个委托

protocol TestManagerDelegate {
    func didCorrectlyComplete(_ testName: TestManager, model: TestModel)
    func didFailWithError(_ error: Error)
}

struct TestManager {

    var delegate: TestManagerDelegate?
    let urlString = "http://numbersapi.com/2/trivia?json"

    func Get(){
        if let url = URL(string: urlString){

            let session = URLSession(configuration: .default)

            let task = session.dataTask(with: url) { (data, response, error) in
                if error != nil{
                    self.delegate?.didFailWithError(error!)
                    return
                }

                if let safeData = data{
                    if let parsedData = self.parseJson(safeData){
                        self.delegate?.didCorrectlyComplete(self, model: parsedData)
                    }
                }
            }
            task.resume()
        }
    }

   func parseJson(_ jsonData: Data) -> TestModel?{
       let decoder = JSONDecoder()
       do {
           let decodedData = try decoder.decode(TestModel.self,  from: jsonData)
           let mes = decodedData.message
           let model = TestModel(message: mes)
           return model

       } catch {
           delegate?.didFailWithError(error)
           return nil
       }
     }

  }
这是testModel数据类。仅获取返回的Json文本

struct TestModel :Decodable{
    let text: String
}
如何将TestManager连接到视图,并让视图像在故事板中那样处理委托?

关于TestModel 协议(在您的上下文中)假定您使用通过JSON获得的所有属性创建模型结构。请求
http://numbersapi.com/2/trivia?json
您将得到如下结果:

{
 "text": "2 is the number of stars in a binary star system (a stellar system consisting of two stars orbiting around their center of mass).",
 "number": 2,
 "found": true,
 "type": "trivia"
}
也就是说,您的模型应该如下所示:

struct TestModel:可解码{
让文本:字符串
编号:Int
让我发现:布尔
let类型:String
}
关于代表 在SwiftUI中,这种方法是无法实现的。相反,开发人员需要调整Combine框架的功能:属性包装器
@ObservedObject
@Published
,以及
observeObject
协议。 你想把你的逻辑放到某个结构中。坏消息是,(目前)
observateObject
AnyObject
协议(即)。您需要将
TestManager
重写为类,如下所示:

类测试管理器:ObservableObject{
// ...
}
只有这样,您才能使用属性包装器在
CurrentView
中使用它:

struct ContentView:View{
@ObservedObject变量管理器=TestManager()
// ...
}
关于TestManager 您的逻辑现在排除了
委托
,因此您需要使用
TestModel
将数据传递给
CustomView
。您可以通过使用属性包装器添加新属性来修改
TestManager

类测试管理器:ObservableObject{
让URL字符串=”http://numbersapi.com/2/trivia?json"
// 1
@发布的var模型:TestModel?
func get(){
如果let url=url(字符串:urlString){
let session=URLSession(配置:。默认值)
让task=session.dataTask(带有:url){[weak self](数据、响应、错误)在
// 2
DispatchQueue.main.async{
如果让safeData=data{
如果让parsedData=self?.parseJson(安全数据){
// 3
self?.model=parsedData
}
}
}
}
task.resume()
}
}
私有func parseJson(jsonData:Data)->TestModel{
let decoder=JSONDecoder()
做{
让decodedData=try decoder.decode(TestModel.self,from:jsonData)
返回解码数据
}抓住{
归零
}
}
}
  • 为了能够“从外部”访问您的模型,在您的案例中是
    ContentView
  • 对异步任务使用
    DispatchQueue.main.async{}
    ,因为不允许从后台线程发布更改;确保在模型更新时从主线程(通过诸如receive(on:)之类的运算符)发布值。
  • 只需使用解析后的模型
  • 然后在
    ContentView
    中使用
    TestManager
    如下:

    struct ContentView:View{
    @ObservedObject变量管理器=TestManager()
    var body:一些观点{
    ZStack{
    颜色(.绿色)
    .edgesIgnoringSafeArea(.all)
    VStack{
    文本(“琐事是:\(self.manager.model?.Text??“未知”))
    按钮(操作:{self.manager.get()}){
    文本(“获取编号2”)
    .font(.title)
    .foregroundColor(.白色)
    .padding()
    .叠加(圆角半径:30)
    .笔划(颜色.白色,线宽:5))
    }
    }
    }
    }
    }
    
    关于HTTP 您使用链接
    http://numbersapi.com/2/trivia?json
    也就是说,请改用
    https
    ,或者添加
    应用程序传输安全设置
    键,并将
    允许任意加载
    参数设置为
    。但这样做是因为http链接根本不起作用

    进一步步骤 根据上面的描述,您可以自己实现错误处理

    完整代码(复制粘贴并执行):
    导入快捷界面
    结构ContentView:View{
    @ObservedObject变量管理器=TestManager()
    var body:一些观点{
    ZStack{
    颜色(.绿色)
    .edgesIgnoringSafeArea(.all)
    VStack{
    文本(“琐事是:\(self.manager.model?.Text??“未知”))
    按钮(操作:{self.manager.get()}){
    文本(“获取编号2”)
    .font(.title)
    .foregroundColor(.白色)
    .padding()
    .叠加(圆角半径:30)
    .笔划(颜色.白色,线宽:5))
    }
    }
    }
    }
    }
    结构内容视图\u预览:PreviewProvider{
    静态var预览:一些视图{
    ContentView()
    }
    }
    类TestManager:ObservableObject{
    让URL字符串=”http://numbersapi.com/2/trivia?json"
    @发布的var模型:TestModel?
    func get(){
    如果let url=url(字符串:urlString){
    let session=URLSession(配置:。默认值)
    让task=session.dataTask(带有:url){[weak self](数据、响应、错误)在
    DispatchQueue.main.async{
    如果让safeData=data{
    如果让parsedData=self?.parseJson(安全数据){
    self?.model=parsedData