How do I add NotificationCenter.default.addObserve in SwiftUI?
When I tried adding observer I get below error
Argument of \'#sele
This worked for me
let NC = NotificationCenter.default
self.NC.addObserver(forName: .NEVPNStatusDidChange, object: nil, queue: nil,
using: self.VPNDidChangeStatus)
func VPNDidChangeStatus(_ notification: Notification) {
}
I use this extension so it's a bit nicer on the call site:
/// 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")
}
The accepted answer may work but is not really how you're supposed to do this. In SwiftUI you don't need to add an observer in that way.
You add a publisher and it still can listen to NSNotification events triggered from non-SwiftUI parts of the app and without needing combine.
Here as an example, a list will update when it appears and when it receives a notification, from a completed network request on another view / controller or something similar etc.
If you need to then trigger an @objc func for some reason, you will need to create a Coordinator
with UIViewControllerRepresentable
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
}
}
I have one approach for NotificationCenter
usage in SwiftUI
.
For more information Apple Documentation
Notification extension
extension NSNotification {
static let ImageClick = NSNotification.Name.init("ImageClick")
}
ContentView
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)
}
}
}
}
DetailView
struct DetailView: View {
var body: some View {
Image(systemName: "wifi")
.frame(width: 30,height: 30, alignment: .center)
.foregroundColor(AppColor.black)
.onTapGesture {
NotificationCenter.default.post(name: NSNotification.ImageClick,
object: nil, userInfo: ["info": "Test"])
}
}
}
It is not SwiftUI-native approach, which is declarative & reactive. Instead you should use NSNotificationCenter.publisher(for:object:) from Combine.
See more details in Apple Documentation
exchange this
self.NC.addObserver(self, selector: #selector(self.VPNDidChangeStatus),
name: .NEVPNStatusDidChange, object: nil)
to
self.NC.addObserver(self, selector: #selector(VPNDidChangeStatus(_:)),
name: .NEVPNStatusDidChange, object: nil)