Search Your Question

Showing posts with label Notification. Show all posts
Showing posts with label Notification. Show all posts

What is KVO?

Key-value observing is the ability for Swift to attach code to variables, so that whenever the variable is changed the code runs. It’s similar to property observers (willSet and didSet ), except KVO is for adding observers outside of the type definition.


KVO isn’t terribly nice in pure Swift code, because it relies on the Objective-C runtime – you need to use @objc classes that inherit from NSObject, then mark each of your properties with @objc dynamic.


For example, we could create a Car class like this:


@objc class Car: NSObject {

    @objc dynamic var name = "BMW"

}


let bmw= Car()

You could then observe that user’s name changing like this:


bmw.observe(\Car.name, options: .new) { car, change in

    print("I'm now called \(car.name)")

}

That asks BMW to watch for new values coming in, then prints the person’s name as soon as the new value is set.


To try it out, just change the car's name to something else:


bmw.name = "Mercedese"

That will print “I’m now called Mercedese.”


Although KVO is unpleasant in pure Swift code, it’s better when working with Apple’s own APIs – they are all automatically both @objc and dynamic because they are written in Objective-C.


However, one warning: even though large parts of UIKit might work with KVO, this is a coincidence rather than a promise – Apple makes no guarantees about UIKit remaining KVO-compatible in the future.

Difference between FCM and APNS

  • FCM is sent as JSON payloads and APNS sends either string or dictionary.
  • FCM has a payload of 2KB while APNS has a payload of 4KB.
  • APNS saves 1 notification per App while FCM saves 100 notifications per device.
  • FCM supports multiple platforms while APNS requires their proprietary platform.
  • Acknowledgment can be sent in FCM if using XMPP, but it's not possible on APNS.

Advatage of FCM

  • Even if the user disallows notification, you can notify your app if the app is running in the foreground (using shouldEstablishDirectChannel).
  • Don't need to create dashboard to send notification on the device.
  • Notification analytics on FCM Dashboard.
  • Easy to create notification payload structure.
  • App Server side handling is easy, Only one key is required for multiple apps and platform (iOS, Android, Web)

What is NSNotification?

Ans :  Apple has provided an Observer Pattern in the Cocoa library called the NSNotificationCenter.

The basic idea is that a listener registers with a broadcaster using some predefined protocol. At some later point, the broadcaster is told to notify all of its listeners, where it calls some function on each of its listeners and passes certain arguments along. This allows for asynchronous message passing between two different objects that don't have to know about one-another, they just have to know about the broadcaster.

NSNotification is like notifying the other class about the changes that will happen if some action takes place in another class.

Simple :

NSNotificationCenter can be thought of as a broadcaster and we can tune into different stations, or channels to listen for any changes.

Example : 

NotificationCenter.default is where all notifications are posted to and are observed from. Each notification must have a unique way to identify themselves. If we were to observe, or listen, to any channel, we would call on the observe method available to us through NotificationCenter.default and perform some type of action based on this listening.

We have two view controllers named VC1 and VC2. We having observer in VC1 and when we select something in VC2, VC2 post notifications to observer methods.

VC1 :

 func setToIndia(notification: NSNotification) {
     cityChosenLabel.text = "India"
 }
 func setToPakistan(notfication: NSNotification) {
     cityChosenLabel.text = "Pakistan"

 }

Now, we create notification.name extension to set unique name to notification.

 extension Notification.Name {
     static let india = Notification.Name("India")
     static let  pakistan = Notification.Name("Pakistan")
 }

Now we add observer methods,


 NotificationCenter.default.addObserver(self, selector:   #selector(setToIndia(notification:)), name: .india, object: nil)

 NotificationCenter.default.addObserver(self, selector:  #selector(setToPakistan(notfication:)), name: .pakistan, object: nil)


VC2:

We will post notification on selecting something here :


 @IBAction func indiaButton(_ sender: Any) {
     NotificationCenter.default.post(name: .india, object: nil)
 }

 @IBAction func pakistanButton(_ sender: Any) {
      NotificationCenter.default.post(name: .pakistan, object: nil
 }


* When indaButton clicked, Notification Center broadcast notification with message to all listeners name India. 

If you didn't understand still, consider notification center is radio station and our mobile device has observer methods so it can listen radio station's voice.

Simple.....Huah.....






Difference between KVO and KVC and Delegate

Ans : There is no way to find any differences between KVC and KVO. Both are different things.

1. KVC - Key Value Coding

We can get and set value of class property using string.

Code for example :

import UIKit

class Employee : NSObject {
    @objc var name = String()
    @objc var age = 0
    @objc var assets = ["ID Card", "Macbook"]

}

We should make sure that Employee inherits from NSObject because it confirms protocol named NSKeyValueCodiing.

We also make sure that @objc should be added as it is objective c runtime for making those properties available for coding. emp.setValue("Manna", forKeyPath: #keyPath(<#T##@objc property sequence#>))

Using KVC,
let emp = Employee()
emp.setValue("Manan", forKey: "name")

Here, we set value of name property using string "name". Here there is chance to misspell property name.

Another way,

emp.setValue("Manna", forKeyPath: #keyPath(Employee.name))

Benefit of this way,  There is no any chance to misspell as it only accepts valid key path other wise it gives compile time error.

Another way,

emp.setValuesForKeys([
                        "name" : "Manan",
                        "age"  : 29

                ])

What will happened, if we have some private properties in class. They are not accessible directly using their value. We have to make extension of class to use their values.
or

@objc private var name = String()

emp.setValue("Manan", forKey: "name")
emp.value(forKey: "name")

We can access private properties as above using KVC. emp.name will give compile time error as name is private,  but using KVC it is possible to access.

We can access array and add item in this array,

let mutableArray = emp.mutableArrayValue(forKeyPath: #keyPath(Employee.assets))
mutableArray.add("Laptop Bag")


2. KVO - Key value observer

When we want to do something when property values changes, we can use KVO concept. We can observer property and on value changed we can take action.

For that,
A special method named observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) should be implemented to the observing class.


self.child1.addObserver(self, forKeyPath: "name",  optional: [.new, .old], context: child1context]


There are some parameters :

  • addObserver:  This is the observing class, usually the self object. 
  • forKeyPath: I guess you can understand what’s this for. It is the string you used as a key or a key path and matches to the property you want to observe. Note that you specify here either a single key, or a key path. 
  • options: an array of NSKeyValueObservingOptions values. 
  • context: This is a pointer that can be used as a unique identifier for the change of the property we observe. Usually this is set to nil or NULL. We’ll see more about this later.
We have to implement  following observerValue method and it is mandatory to adopt KVO concept.




Sometimes, we don't want notification when some  property value changed. Then we do following :


Credit : HackerMoon

Know more about KVO : Click here

Difference between Delegate, Notification and KVO


Use a delegate if you want to talk to only one object. For example, a tableView has a delegate - only one object should be responsible for dealing with it.

Use notifications if you want to tell everyone that something has happened. For example in low memory situations, a notification is sent telling your app that there has been a memory warning. Because lots of objects in your app might want to lower their memory usage it's a notification.

I don't think KVO is a good idea at all and try not to use it but, if you want to find out if a property has changed you can listen for changes.

Which delegate method called when I click on push notifications?

Ans : 
Different app delegate method called depends on following scenarios

For silent notification : 

App is in Foreground
No system alert shown
application:didReceiveRemoteNotification:fetchCompletionHandler: is called

App is in Background
System alert is shown
application:didReceiveRemoteNotification:fetchCompletionHandler: is called

App is in Suspended
App state changes to Background
System alert is shown
application:didReceiveRemoteNotification:fetchCompletionHandler: is called

App is Not Running because killed by user
System alert is shown
No callback is called

Normal Push Notification (no content-available) :

App is in Foreground
No system alert shown
application:didReceiveRemoteNotification:fetchCompletionHandler: is called

App is in Background or Suspended
System alert is shown
No method is called, but when user tap on the push and the app is opened
application:didReceiveRemoteNotification:fetchCompletionHandler: is called

App is in Not Running
System alert is shown
No method is called, but when user tap on the push and the app is opened
application:didFinishLaunchingWithOptions: then application:didReceiveRemoteNotification:fetchCompletionHandler: are both called

Local Notification in iOS

Ans : 

Q.
 what the best way to Scheduled more than one notification but not remove the previous one?
A. Use different identifier

Different type of request access under UNAuthorizationOptions like .alert, .badge, .sound and .carplay.

let center =  UNUserNotificationCenter.current()a
center.requestAuthorization(options: [.alert, .sound, .badge]) { (result, error) in

 //handle result of request failure

}

UNNotificationRequest helps to create notification request. Which requires 3 information like an identifier, content and trigger.

1. identifier : It is unique for every notification. If we send another notification with same identifier it remove existing notification and replace it with new one.

2. content : display it in banner and main attributes are title, subtitle, body and attachment media. Using UNMutableNotificationContent we can define content.

3. trigger : the event that will trigger the notification to be displayed to the user. There are 3 classes as UNTimeIntervalNotificationTrigger,UNCalendarNotificationTrigger,UNLocationNotificationTrigger which are subclass of  UNNotificationTrigger.

example of creating local notification :

//get the notification center
let center =  UNUserNotificationCenter.current()

//create the content for the notification
let content = UNMutableNotificationContent()
content.title = " Jurassic Park"
content.subtitle = "Lunch"
content.body = "Its lunch time at the park, please join us for a dinosaur feeding"
content.sound = UNNotificationSound.default()

//notification trigger can be based on time, calendar or location
let trigger = UNTimeIntervalNotificationTrigger(timeInterval:2.0, repeats: false)

//create request to display
let request = UNNotificationRequest(identifier: "ContentIdentifier", content: content, trigger: trigger)

//add request to notification center
center.add(request) { (error) in
    if error != nil {
        print("error \(String(describing: error))")
    }
}

-> UNUserNotificationCenterDelegate having 2 methods which is used to display notification when app is in foreground. (WillPresent delegate method is used for display notification when app in foreground).



Explain Apple push notification working

Ans : Push notifications allow developers to reach users and perform small tasks even when users aren’t actively using an app.

In iOS 10, User can do following task :

  • Display a short text message
  • Play a notification sound
  • Set a badge number on the app’s icon
  • Provide actions the user can take without opening the app
  • Show a media attachment
  • Be silent, allowing the app to wake up in the background and perform a task
Now following steps to follow to configure push notification :

1. Create app id in developer account with your app bundle id. Push notification entitlement must be enabled for this app id. (or another way for go to App Settings > Capabilities and enable push notification switch). You also have to create CSR(Certificate Signing Request) file from your keychain and assign to this app id push notification feature in developer account.

2. Now in terms of coding, first we need to ask to user for allowing user notification. After allowing, we need to register for remote notification. If all goes good, system provides you 'token' which is address of this app for this device.

3. In code, first import usernotification. Then for registering for remote notification, in didFnishLaunchingWithOptions

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge])  {
    (granted, error) in
   
       print("Permission granted: \(granted)")
    
       guard granted else { return }
       self.getNotificationSettings()

  }

 func getNotificationSettings()  {
       UNUserNotificationCenter.current().getNotificationSettings { (settings) in
       print("Notification settings: \(settings)")
       guard settings.authorizationStatus == .authorized else { return }
       UIApplication.shared.registerForRemoteNotifications()
  }


4. If registered for remote notification successfully, then one of the following two method will be called,

func application(_ application: UIApplication,
                 didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)  {

       let tokenParts = deviceToken.map { data -> String in
              return String(format: "%02.2hhx", data)
        }

       let token = tokenParts.joined()
       print("Device Token: \(token)")
}

func application(_ application: UIApplication,
                 didFailToRegisterForRemoteNotificationsWithError error: Error)  {
  print("Failed to register: \(error)")
}

5. Device token is provided by APNS and this token will be converted to string. This device token shold be sent to application server or stored to database on server side.

Now lets study about payload or notification message,

Payload looks like :

{
  "aps": {
    "alert": "Breaking News!",
    "sound": "default",
    "link_url": "https://raywenderlich.com"
  }
}

aps is fixed key in payload dictionary json. aps is also dictionary itself.

alert : Display text message
sound : Which sound when notification come
link_url : custom key, we can any such custom key for data
badge : number of count of badge that is displayed on app icon
category : which type of custom action notification have

Payload maximum size is 4096 kb (4 mb).


Now what when notification comes

1. If app is closed didFinishLaunchingWithOptions is called.
2. If open in background or foreground, then didReceiveRemoteNotification is called.

For 1st case,

In didFinishLaunchingWithOptions method
// Check if launched from notification

if let notification = launchOptions?[.remoteNotification] as? [String: AnyObject] {

  let aps = notification["aps"] as! [String: AnyObject]
  _ = NewsItem.makeNewsItem(aps)

  (window?.rootViewController as? UITabBarController)?.selectedIndex = 1
}

For 2nd case,

In didReceiveRemoteNotification,

let aps = userInfo["aps"] as! [String: AnyObject]
  _ = NewsItem.makeNewsItem(aps)

Actionable Notification

Actionable notifications let you add custom buttons to the notification. You can put reply,retweet,like button as you seen our favourite apps. This type of notification can be defined by Category.

In this type notification, we have to register category like following instead of UIApplication.shared.registerForRemoteNotifications().

func registerForPushNotifications() {
  UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
    (granted, error) in   
    print("Permission granted: \(granted)")
 
    guard granted else { return }
 
    // 1
    let viewAction = UNNotificationAction(identifier: viewActionIdentifier,
                                          title: "View",
                                          options: [.foreground])
 
    // 2
    let newsCategory = UNNotificationCategory(identifier: newsCategoryIdentifier,
                                              actions: [viewAction],
                                              intentIdentifiers: [],
                                              options: [])
    // 3
    UNUserNotificationCenter.current().setNotificationCategories([newsCategory])
 
    self.getNotificationSettings()
  }
}


Above things is not enough for taking action on button. We have to add extension of UNUserNotificationCenterDelegate.

Silent Notification 

If we want to do something task without knowing to user in background, then we can send silent notification to user device. For this background modes of push notification must be checked. For push notification aps, there is key named content-available. That's value should be 1 for silent notification.

For more detail, click here.



Difference between Delegate and NSNotification

Ans :  A delegate uses protocol and creates a has-a relationship between two classes. Benefit of delegate is that we can return something back to the owning class.
Notification is like point to multi-point communication. Notification is one way  of message transmitting way.

Delegates create relationship between two classes. Notifications are used to send events to one or many classes.

We have to use delegate to specified known object. Notification for all object.

Delegate is like talking over telephone. Notification is like radio station.  

Coding of NSNotificationCenter :

[[NSNotificationCenter defaultCenter] addObjserver:self selector:@selector(useNotificationWithString:)  name:@”TimeOut” object:nil];

For BroadCast,

[[NSNotificationCenter defaultCenter] postNotificationName:@”TimeOut” object:nil userInfo:dict];

-(void) useNotificationWithString:(NSNotification *)notification
{
            dict = [notification userInfo];
}

To Remove observer,
[[NSNotificationCenter defaultCenter] removeObserver];