如何在 SwiftUI 中设置 addObserver?
Posted
技术标签:
【中文标题】如何在 SwiftUI 中设置 addObserver?【英文标题】:How to set addObserver in SwiftUI? 【发布时间】:2020-03-08 03:00:42 【问题描述】:如何在 SwiftUI 中添加 NotificationCenter.default.addObserve?
当我尝试添加观察者时,出现以下错误
“#selector”的参数指的是实例方法“***DidChangeStatus” 没有暴露给 Objective-C
但是当我在 func 前面添加 @objc 时,我得到以下错误
@objc 只能与类成员、@objc 协议和 类的具体扩展
这是我的代码
let NC = NotificationCenter.default
var body: some View
VStack()
.onAppear
self.NC.addObserver(self, selector: #selector(self.***DidChangeStatus),
name: .NE***StatusDidChange, object: nil)
@objc func ***DidChangeStatus(_ notification: Notification)
// print("***DidChangeStatus", ***Manager.shared.status)
【问题讨论】:
参观一下这可能会有所帮助 -***.com/questions/38980887/… 【参考方案1】:交换这个
self.NC.addObserver(self, selector: #selector(self.***DidChangeStatus),
name: .NE***StatusDidChange, object: nil)
到
self.NC.addObserver(self, selector: #selector(***DidChangeStatus(_:)),
name: .NE***StatusDidChange, object: nil)
【讨论】:
【参考方案2】:这不是 SwiftUI 原生的方法,它是声明式和反应式的。相反,您应该使用 Combine 中的 NSNotificationCenter.publisher(for:object:)。
在Apple Documentation查看更多详情
【讨论】:
【参考方案3】:这对我有用
let NC = NotificationCenter.default
self.NC.addObserver(forName: .NE***StatusDidChange, object: nil, queue: nil,
using: self.***DidChangeStatus)
func ***DidChangeStatus(_ notification: Notification)
【讨论】:
【参考方案4】:接受的答案可能有效,但实际上并不是您应该这样做。在 SwiftUI 中,您不需要以这种方式添加观察者。
您添加一个发布者,它仍然可以侦听从应用程序的非 SwiftUI 部分触发的 NSNotification 事件,而无需合并。
这里作为一个例子,列表将在它出现时更新,当它收到通知时,来自另一个视图/控制器上的已完成网络请求或类似的东西等。
如果您出于某种原因需要触发@objc func,则需要使用UIViewControllerRepresentable
创建一个Coordinator
struct YourSwiftUIView: View
let pub = NotificationCenter.default
.publisher(for: NSNotification.Name("YourNameHere"))
var body: some View
List()
ForEach(userData.viewModels) viewModel in
SomeRow(viewModel: viewModel)
.onAppear(perform: loadData)
.onReceive(pub) (output) in
self.loadData()
func loadData()
// do stuff
【讨论】:
这行得通。然后,您可以像这样发布通知 -> self.nc.post(name: Notification.Name("RemoteContatcsReceived"), object: nil) 使用 xCode 11.5 我不必使用 @objc 耶! 如果你将它移动到一个状态对象中,那么它不会搞砸你的预览,因为状态对象在预览时没有初始化。NotificationCenter.publisher(for:object:)
确实使用Combine
。您可以从任何您想要的代码中调用一个Objective C 函数。大概您指的是定义一个目标C函数。即使这与UIViewControllerRepresentable
或协调员完全无关。你只需要在一个类中定义函数。
struct YourSwiftUIView: View @State updateYourSwiftUIView: Bool = false ... func loadData() // 做些事情 updateYourSwiftUIView.toggle() 【参考方案5】:
我有一种在SwiftUI
中使用NotificationCenter
的方法。
欲了解更多信息Apple Documentation
通知扩展n
extension NSNotification
static let ImageClick = Notification.Name.init("ImageClick")
内容视图
struct ContentView: View
var body: some View
VStack
DetailView()
.onReceive(NotificationCenter.default.publisher(for: NSNotification.ImageClick))
obj in
// Change key as per your "userInfo"
if let userInfo = obj.userInfo, let info = userInfo["info"]
print(info)
详细视图
struct DetailView: View
var body: some View
Image(systemName: "wifi")
.frame(width: 30,height: 30, alignment: .center)
.foregroundColor(.black)
.onTapGesture
NotificationCenter.default.post(name: NSNotification.ImageClick,
object: nil, userInfo: ["info": "Test"])
【讨论】:
很好的答案!一件事:在 Swift 中使用 Notification 而不是 NSNotification。【参考方案6】:我使用这个扩展,所以它在呼叫站点上更好一点:
/// Extension
extension View
func onReceive(_ name: Notification.Name,
center: NotificationCenter = .default,
object: AnyObject? = nil,
perform action: @escaping (Notification) -> Void) -> some View
self.onReceive(
center.publisher(for: name, object: object), perform: action
)
/// Usage
struct MyView: View
var body: some View
Color.orange
.onReceive(.myNotification) _ in
print(#function)
extension Notification.Name
static let myNotification = Notification.Name("myNotification")
【讨论】:
以上是关于如何在 SwiftUI 中设置 addObserver?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 中设置 ScrollView 的 contentInset
在 SwiftUI 中,如何在 XcodePreview 中设置 editMode 的环境变量