是否可以在 SwiftUI 中提供服务并将数据推送到视图并更新 UI?

Posted

技术标签:

【中文标题】是否可以在 SwiftUI 中提供服务并将数据推送到视图并更新 UI?【英文标题】:Is it possible to have a Service in SwiftUI and push data to a View and update the UI? 【发布时间】:2019-07-18 17:42:17 【问题描述】:

我有一个获取数据并将数据发送到后端的服务文件。是否可以将推送数据从服务推送到视图并让 UI 像 @State 一样获取更改(不像全局变量)。

@EnviornmentObject 不能以只读方式工作 全局变量不起作用,因为不通知 UI

import SwiftUI
import SocketIO
import Combine

let manager = SocketManager(socketURL: URL(string: "http://localhost:30000/ios")!, config: [.log(true), .compress])
let socket = manager.defaultSocket

class Socket: BindableObject 
    let didChange = PassthroughSubject<Socket,Never>()
    var sliderValue: Float = 6 
        willSet 
            print(newValue)
            didChange.send(self)
        
    
    static let sharedInstance = Socket()
    init() 

        socket.on(clientEvent: .connect) data, ack in
            print("socket connected")
            self.sliderValue = 8 
        

    


    func establishConnection() 
        socket.connect()
    

    func closeConnection() 
        socket.disconnect()
    

主页视图:

import SwiftUI

struct HomeView : View 
    @EnvironmentObject var socketData: Socket

    var body: some View 
        VStack 
            Text("Hello World")
            Slider(value: $socketData.sliderValue, from: 0.0, through: 10.0)
            Text(String(socketData.sliderValue))
        
    

【问题讨论】:

哇。 @EnvironmentObject 正确的。更新模型,发给UI,yada,yada。问题是另外一回事 - 请记住,@State 是针对单个 View 的局部变量。所以也许......您是否正确更新了模型状态? Ae 你正在处理一个UIKit 的前景,以寻求非常不同的东西吗?你为什么说环境变量是只读的?他们不是。请向我们展示更多要复制的代码。 我以为我读到它是只读的。我是 swift 新手,但我更新了答案 不要发布一个可能没有帮助的冗长答案,而是看看这个答案 - ***.com/questions/56725084/… - Slider 正在更新 BindableObject,它是 @EnvironmentObject@ObjectBinding 一个。 (是的,现在在 beta 4 中,它需要 willSet PassthruoghSubject。欢迎来到 Swiftui 的前沿!) 我按照那里告诉的那样做了,但是当套接字连接时,用户界面没有更新 你是在主线程上更新模型吗?这是使用BindableObject 的唯一警告——也是为什么我不确定这些是否有帮助的原因。 (我不使用套接字,但知道它们是什么——我自 1984 年以来一直在 IT 987654336@ 可能有用吗?) 【参考方案1】:

我仍然有无法从套接字获取数据但正常字符串工作的问题我将为这个问题打开一个新问题: How to fix 'Cannot convert value of type '[Any]' to type 'String' in coercion' error in swift

我确实不得不使用 didSet 这里是代码:

let manager = SocketManager(socketURL: URL(string: "http://localhost:30000/ios")!, config: [.log(true), .compress])
let socket = manager.defaultSocket


class Socket: BindableObject 
    let didChange = PassthroughSubject<Socket,Never>()
    var days: String = "Loading..." 
        didSet 
            didChange.send(self)
        
    
    static let sharedInstance = Socket()
    init() 

        socket.on(clientEvent: .connect) data, ack in
            print("socket connected")
        
        socket.on("dailyWeather") data, ack in
            print("just a test")
            self.days = "cur"
        
    


    func establishConnection() 
        socket.connect()
    

    func closeConnection() 
        socket.disconnect()
    

【讨论】:

【参考方案2】:

您可以使您的 Socket 具有 messagePublisher 以便使用传入消息更新子视图。

class Socket 
    static let sharedInstance = Socket()
    public let messagePublisher = PassthroughSubject<Message, Never>()
    init() 

      socket.on(clientEvent: .connect) data, ack in
          print("socket connected")
          let message = data as! Message
          messagePublisher.send(message)
      

    

然后让您的孩子像这样订阅传入的消息:

Socket.sharedInstance.assign(to: \.message, on: messageModel)

其中MessageModel 符合BindableObject 协议

【讨论】:

我必须在哪里添加这一行?Socket.sharedInstance.assign(to: \.message, on: messageModel) @TobiasBauer 您可以将其添加到您想使用套接字的子视图中。 DemoView 可能有一个属性 @ObjectBinding var model: MessageModel。并且MessageModel 应该有一个属性message,您可以在其中分配套接字。 我更新了上面的代码,但是我有这个错误:无法将类型'WritableKeyPath'的值转换为预期的参数类型'ReferenceWritableKeyPath<_>'

以上是关于是否可以在 SwiftUI 中提供服务并将数据推送到视图并更新 UI?的主要内容,如果未能解决你的问题,请参考以下文章

检测在 SwiftUI 中点击的系统警报按钮

从 SwiftUI 应用程序中更改推送通知授权

SwiftUI,ScrollView 在 ZStack 中向上推送 VStack 图像

Ionic 可以在没有推送服务的情况下接收推送通知吗?

在 swiftui 中 2 秒后推送视图

D7的移动推送通知服务提供商[关闭]