How to Set Addobserver in Swiftui

How to set addObserver in SwiftUI?

This worked for me

   let NC = NotificationCenter.default



self.NC.addObserver(forName: .NEVPNStatusDidChange, object: nil, queue: nil,
using: self.VPNDidChangeStatus)


func VPNDidChangeStatus(_ notification: Notification) {


}

Refresh SwiftUI View Based on Local Notification

The transitive nature of SwiftUI views makes doing things like trying to capture a reference to self in your view's init problematic. Here are a couple solutions:

Option 1

Keep everything in the View:

struct ContentView: View {
@State private var isDataImported: Bool = false
@State private var cancellable : AnyCancellable?

var body: some View {
Group {
if isDataImported {
Text("Has data")
} else {
Text("Does not have data")
}
}.onAppear {
cancellable = NotificationCenter.default.publisher(for: .onDataImported)
.receive(on: RunLoop.main)
.sink { notification in
self.isDataImported = true
}
NotificationCenter.default.post(name: .onDataImported, object: nil)
}
}
}

Option 2

This is usually what I'd do, moving it to a view model, so that you can keep onAppear a little cleaner. Because the view model is a class and have a reliable, reference-based lifetime, the assignment to self is less problematic:

class ViewModel: ObservableObject {
@Published var isDataImported: Bool = false
private var cancellable : AnyCancellable?

init() {
cancellable = NotificationCenter.default.publisher(for: .onDataImported)
.receive(on: RunLoop.main)
.sink { notification in
self.isDataImported = true
}
}
}

struct ContentView : View {
@StateObject var viewModel = ViewModel()

var body: some View {
Group {
if viewModel.isDataImported {
Text("Has data")
} else {
Text("Does not have data")
}
}.onAppear {
NotificationCenter.default.post(name: .onDataImported, object: nil)
}
}
}

Why I can't receive a notification on an observer class inside a View struct in SwiftUI?

Notifications matched by object, so if you subscribe by one object but post with another object, then subscriber is not fired.

Here is fixed variant. Tested with Xcode 12.1.

    NotificationCenter.default.addObserver(observerA, 
selector: #selector(ObserverClassA.receivedNotification(notification:)),
name: Notification.Name("CustomNotification"),
object: nil) // << subscribe for all

let notificationToPost = Notification(name: Notification.Name("CustomNotification"), object: "This is the message", userInfo: nil)
NotificationCenter.default.post(notificationToPost)

SwiftUI with NotificationCenter publishers

@State is not ready yet in init, so it cannot be used for such purposes. The approach can be as follows:

var cancellables = Set<AnyCancellable>()
init() {
NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)
.sink(receiveValue: { _ in
print(">> in init")
})
.store(in: &cancellables)
}

in such defined cancellables you can store all subscribers created in init, but you will not be able to use it later in code, but this approach is good for once defined notification handlers.

How to subscribe to EventKit changes in SwiftUI?

You have a couple of options. One is to use an ObservableObject that can have @objc functions and declare it as the delegate for the notifications:

struct ContentView: View {
@StateObject private var eventDelegate = EventDelegate()

var body: some View {
Text("Hello, world!")
.padding()
}
}

class EventDelegate: ObservableObject {
let eventStore = EKEventStore()

init() {
NotificationCenter.default.addObserver(self, selector: #selector(observeEvents), name: .EKEventStoreChanged, object: eventStore)
//remember to clean up your observers later
}

@objc func observeEvents() {
print("called with updated events")
}
}

A second option would be to use NotificationCenter's publisher inside your View. Note this example is incomplete, as it's unclear what actions you want to take with the notification, but it's a template to get you started:

struct ContentView: View {
@State private var eventStore = EKEventStore() //normally wouldn't use @State for a reference type like this, but it seems pointless to recreate it
@State private var pub : NotificationCenter.Publisher?

var body: some View {
Text("Hello, world!")
.padding()
.onAppear {
pub = NotificationCenter.default.publisher(for: .EKEventStoreChanged, object: eventStore)
//use sink or assign here
}
}
}

NSNotificationCenter addObserver in Swift

It's the same as the Objective-C API, but uses Swift's syntax.

Swift 4.2 & Swift 5:

NotificationCenter.default.addObserver(
self,
selector: #selector(self.batteryLevelChanged),
name: UIDevice.batteryLevelDidChangeNotification,
object: nil)

If your observer does not inherit from an Objective-C object, you must prefix your method with @objc in order to use it as a selector.

@objc private func batteryLevelChanged(notification: NSNotification){     
//do stuff using the userInfo property of the notification object
}

See NSNotificationCenter Class Reference, Interacting with Objective-C APIs

How to set an observer on the queue player's currentItem?

Representable, which is struct, cannot be used KVO observer. You can to use Coordinator as observer.

Here is modified code with possible approach:

struct VideoPlayerS : UIViewControllerRepresentable {

var work : WorkoutDeS
@Binding var player : AVQueuePlayer
var playerLayer = AVPlayerLayer()

public func makeUIViewController(context: Context) -> AVPlayerViewController {
let items = [

AVPlayerItem(url: URL(fileURLWithPath: String(work.url1))),
AVPlayerItem(url: URL(fileURLWithPath: String(work.url2)))

]
let player = AVQueuePlayer(items: items)
let controller = AVPlayerViewController()

DispatchQueue.main.async {
self.player = player
}
controller.player = player
controller.videoGravity = .resizeAspectFill

player.actionAtItemEnd = .none
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player.currentItem, queue: .main) { _ in
self.player.seek(to: CMTime.zero)
self.player.play()
}

player.currentItem?.addObserver(context.coordinator, forKeyPath: "status", options: [.new], context: nil)

player.play()
return controller
}

func makeCoordinator() -> Coordinator {
Coordinator(owner: self)
}

class Coordinator: NSObject {
var owner : VideoPlayerS

init(owner: VideoPlayerS) {
self.owner = owner
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
guard let item = object as? AVPlayerItem else { return }

if keyPath == "status" {
print("Hello")
item.removeObserver(self, forKeyPath: "status")
}
}
}

func rewindVideo(notification: Notification) {
playerLayer.player?.seek(to: .zero)
}

public func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<VideoPlayerS>) {

}
}

Swift 4 - Notification Center addObserver issue

You can improve your code with these steps:

extension Notification.Name {
static let dataDownloadCompleted = Notification.Name(
rawValue: "dataDownloadCompleted")
}

And use it like this:

let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self,
selector: #selector(YourClass.sayHello),
name: .dataDownloadCompleted,
object: nil)

But as was already pointed out, issue is solved by changing to #selector



Related Topics



Leave a reply



Submit