Search Your Question

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)

GIT Interview Questions 2

  1. GIT Commit command
    The command that is used to write a commit message is “git commit -a”
    Now explain about -a flag by saying -a on the command line instructs git to commit the new content of all tracked files that have been modified. Also, mention you can use “git add <file>” before git commit -a if new files need to be committed for the first time.

  2. How can you fix a broken commit?
    In order to fix any broken commit, use the command “git commit --amend”. When you run this command, you can fix the broken commit message in the editor.

  3.  Basic Git commands:

    CommandFunction
    git rm [file]deletes the file from your working directory and stages the deletion.
    git log list the version history for the current branch.

    git show [commit]  

    shows the metadata and content changes of the specified commit.

    git tag [commitID] 

    used to give tags to the specified commit.

    git checkout [branch name]

    git checkout -b [branch name]

    used to switch from one branch to another.

    creates a new branch and also switches to it.



  4. In Git how do you revert a commit that has already been pushed and made public?
    There can be two approaches to tackle this question and make sure that you include both because any of the below options can be used depending on the situation:

    Remove or fix the bad file in a new commit and then push it to the remote repository. This is the most obvious way to fix an error. Once you have made necessary changes to the file, then commit it to the remote repository using the command: git commit -m “commit message”

    Also, you can create a new commit that undoes all changes that were made in the bad commit. To do this use the command

    git revert <name of bad commit>

  5. What is the difference between git pull and git fetch?
    Git pull command pulls new changes or commits from a particular branch from your central repository and updates your target branch in your local repository.

    Git fetch is also used for the same purpose but it works in a slightly different way. When you perform a git fetch, it pulls all new commits from the desired branch and stores it in a new branch in your local repository. If you want to reflect these changes in your target branch, git fetch must be followed with a git merge. Your target branch will only be updated after merging the target branch and fetched branch. Just to make it easy for you, remember the equation below:

    Git pull = git fetch + git merge

  6. What is git stash?
    Often, when you’ve been working on part of your project, things are in a messy state and you want to switch branches for some time to work on something else. The problem is, you don’t want to do a commit of half-done work just so you can get back to this point later. The answer to this issue is Git stash.

    Stashing takes your working directory that is, your modified tracked files and staged changes and saves it on a stack of unfinished changes that you can reapply at any time.

  7. What is the function of ‘git stash apply’?
    If you want to continue working where you had left your work then ‘git stash apply‘ command is used to bring back the saved changes onto your current working directory.

  8. What is git stash drop?
    Git ‘stash drop’ command is used to remove the stashed item. It will remove the last added stash item by default, and it can also remove a specific item if you include it as an argument.

    Now give an example.

    If you want to remove a particular stash item from the list of stashed items you can use the below commands:
  • git stash list: It will display the list of stashed items like:
  • stash@{0}: WIP on master: 049d078 added the index file
  • stash@{1}: WIP on master: c264051 Revert “added file_size”
  • stash@{2}: WIP on master: 21d80a5 added number to log

    If you want to remove an item named stash@{0} use command git stash drop stash@{0}.

  1. Can you explain the Gitflow workflow?
    To record the history of the project, Gitflow workflow employs two parallel long-running branches – master and develop:

    Master – this branch is always ready to be released on LIVE, with everything fully tested and approved (production-ready).

    Hotfix – these branches are used to quickly patch production releases. These branches are a lot like release branches and feature branches except they’re based on master instead of develop.

    Develop – this is the branch to which all feature branches are merged and where all tests are performed. Only when everything’s been thoroughly checked and fixed it can be merged to the master.

    Feature – each new feature should reside in its own branch, which can be pushed to the develop branch as their parent one.

  2. What is Git fork? What is the difference between fork, branch, and clone?
    A fork is a copy of a repository. Normally you fork a repository so that you are able to freely experiment with changes without affecting the original project. Most commonly, forks are used to either propose changes to someone else’s project or to use someone else’s project as a starting point for your own idea.

    git cloning means pointing to an existing repository and make a copy of that repository in a new directory, at some other location. The original repository can be located on the local file system or on remote machine accessible supported protocols. The git clone command is used to create a copy of an existing Git repository.

    In very simple words, git branches are individual projects within a git repository. Different branches within a repository can have completely different files and folders, or it could have everything the same except for some lines of code in a file.

  3. What is the difference between rebasing and merge in Git?
    In Git, the rebase command is used to integrate changes from one branch into another. It is an alternative to the “merge” command. The difference between rebasing and merge is that rebase rewrites the commit history in order to produce a straight, linear succession of commits.

    Merging is Git’s way of putting a forked history back together again. The git merge command helps you take the independent lines of development created by git branch and integrate them into a single branch.

  4. What is git cherry-pick?
    The command git cherry-pick is normally used to introduce particular commits from one branch within a repository onto a different branch. Another common use is to forward- or back-port commits from a maintenance branch to a development branch. This is in contrast with other ways such as merge and rebase which normally apply many commits onto another branch.

    Consider:

    git cherry-pick <commit-hash>

  5. How do you squash the last N commits into a single commit?
    There are two options to squash the last N commits into a single commit include both of the below-mentioned options in your answer
    If you want to write the new commit message from scratch use the following command

    git reset –soft HEAD~N &&git commit

    If you want to start editing the new commit message with a concatenation of the existing commit messages then you need to extract those messages and pass them to Git commit for that I will use

    git reset –soft HEAD~N &&git commit –edit -m”$(git log –format=%B –reverse .HEAD@{N})”

  6. How do I rename a local Git branch?
    Here are the steps to rename the branch:

    Switch to the branch which needs to be renamed

    git branch -m <new_name>
    git push origin :<old_name>
    git push origin <new_name>:refs/heads/<new_name>

Difference between MVC and Viper architecture

What is MVVM?

MVVM - Model View ViewModel

Advantage : 

Better Separation of Concerns
In a project built with the Model-View-Controller pattern, you are often faced with the question which code goes where. Code that doesn’t fit or belong in the model or view layer is often put in the controller layer. This inevitably leads to fat controllers that are difficult to test and manage.

The MVVM pattern presents a better separation of concerns by adding view models to the mix. The view model translates the data of the model layer into something the view layer can use. The controller is no longer responsible for this task.

Improved Testability
View controllers are notoriously hard to test because of their relation to the view layer. By migrating data manipulation to the view model, testing becomes much easier. Testing view models is easy. Because a view model doesn’t have a reference to the object it is owned by, it easy to write unit tests for a view model.

Another, and often overlooked, benefit of MVVM is improved testability of view controllers. The view controller no longer depends on the model layer, which makes them easier to test.

Transparent Communication
The responsibilities of the view controller are reduced to controlling the interaction between the view layer and the model layer, glueing both layers together.

The view model provides a transparent interface to the view controller, which it uses to populate the view layer and interact with the model layer. This results in a transparent communication between the four layers of your application.

There are some rules you know when using MVVM

Rule1 : The view does not know about the controller it is owned by. Remember that views are supposed to be dumb. They only know how to present the data they are given to the user.
Rule 2 : The controller does not know about the model. This is what separates MVC from MVVM.
Rule 3 : The model does not know about the view model it is owned by.
Rule 4 : The view model owns the model. When using the Model-View-Controller pattern, the model is usually owned by the controller.
Rule 5 : The view controller owns the view. This relationship remains unchanged when using the Model-View-ViewModel pattern.
Rule 6 : And, finally, the controller owns the view model. It interacts with the model layer through one or more view models.

Download task when app is inactive

 https://developer.apple.com/documentation/foundation/url_loading_system/downloading_files_in_the_background


For the background download, there is beginBackgroundTaskWithExpirationHandler: that is specifically designed to do that. When you use it, you will get few more minutes to execute whatever you need (after that limit, your application will get terminated no matter what).

You can write following methods:

func beginBackgroundTask() -> UIBackgroundTaskIdentifier {
    return UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({})
}

func endBackgroundTask(taskID: UIBackgroundTaskIdentifier) {
    UIApplication.sharedApplication().endBackgroundTask(taskID)
}

When you want to use it, you just simple begin / end the task when starting / finishing the download call:

// Start task
let task = self.beginBackgroundTask()

// Do whatever you need
self.someBackgroundTask()

// End task
self.endBackgroundTask(task)

Hope it helps!

What is SSL Pinning and How to implement it?

SSL stands for Secure Socket Layer, which is a protocol for creating an encrypted connection between client and server. It ensures that all data pass in network will be private and integral.

How SSL works? When client establishes the connection with server (called SSL handshake):

  1. Client connects to server and requests server identify itself.
  2. Server sends certificate to client (include public key)
  3. Client checks if that certificate is valid. If it is, client creates a symmetric key (session key), encrypts with public key, then sends back to server
  4. Server receives encrypted symmetric key, decrypts by its private key, then sends acknowledge packet to client
  5. Client receives ACK and starts the session

Using SSL, the client will allow the connection only from trusted sources that have the valid certificate. And it looks good for most cases. But what if someone stands between client and server, and acts like they are the real server? Let's call client is C, server is S and the attacker is A.

In step 1, instead of sending packet to S, A can catch the packet and pretend it as S. What if instead of receiving certificate from S, client C will receive fake certificate from A and believe it's valid. A can make C think that it is communicating with S, but actually all connection flows will be directed to attacker A.

Hence, SSL pinning can be the solution to prevent Man-In-The-Middle (MITM) attack. SSL pinning will ensure that client connect with designated server. The main key of SSL pinning that server certificate will be saved in app bundle. Then, when client receives certificate from server, it then compares 2 certificates to make sure that they are the same before establishing the connection.

URLSession

For NSURLSession, the main method to handle SSL pinning is URLSession:didReceiveChallenge:completionHandler:delegate. Set your class to conform URLSessionDelegate and paste this function to your class:


func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
        if let serverTrust = challenge.protectionSpace.serverTrust {
            var secresult = SecTrustResultType.invalid
            let status = SecTrustEvaluate(serverTrust, &secresult)
            
            if (errSecSuccess == status) {
                if let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
                    let serverCertificateData = SecCertificateCopyData(serverCertificate)
                    let data = CFDataGetBytePtr(serverCertificateData);
                    let size = CFDataGetLength(serverCertificateData);
                    let cert1 = NSData(bytes: data, length: size)
                    let file_der = Bundle.main.path(forResource: "name-of-cert-file", ofType: "cer")
                    
                    if let file = file_der {
                        if let cert2 = NSData(contentsOfFile: file) {
                            if cert1.isEqual(to: cert2 as Data) {
                                completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:serverTrust))
                                return
                            }
                        }
                    }
                }
            }
        }
    }
    
    // Pinning failed
    completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}

This function will “requests credentials from the delegate in response to an authentication request from the remote server.” We will compare the certificate from server with the one that saved in app bundle. If 2 certificates are identical, the authentication will let it pass and client can connect to server.

Types of SSL Pinning(What to Pin)?

Pin the certificate: You can download the server’s certificate and put this in your app bundle. At runtime, the app compares the server’s certificate to the one you’ve embedded.

One disadvantage of SSL pinning is that you have to save the certificate in the app. Whenever the certificate is updated, we need to release new version of app. But this also leads to another problem: what we do with older version?
  • Maintain the old certificate for a time, until we make sure all users have downloaded new version already.

Pin the public key: You can retrieve the certificate’s public key and include it in your code as a string. At runtime, the app compares the certificate’s public key to the one hard-coded hash string in your code.

Explain NSOPERATION Priority.

Ans : 

All operations may not be equally important. Setting the queuePriority property will promote or defer an operation in an NSOperationQueue according to the following rankings:

public enum NSOperationQueuePriority : Int {
    case VeryLow
    case Low
    case Normal
    case High
    case VeryHigh

}

The operations with high priority will be executed first.

let backgroundOperation = NSOperation()
backgroundOperation.queuePriority = .Low

let operationQueue = NSOperationQueue.mainQueue()
operationQueue.addOperation(backgroundOperation)

Swift Initializers

Ans :

Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that is required before the new instance is ready for use.

Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties cannot be left in an indeterminate state.

Initializers : Initializers, are like special methods that can be called to create a new instance of a particular type.

init() {
// perform some initialization here
}

Customizing Initialization :

struct Human {
    var gender:Gender
    var age:Int = 10
    
    init(age:Int) { // initializer 1
        self.age = age
        self.gender = .unknown
    }
    
    init(age:Int, gender:Gender) { // initializer 2
        self.age = age
        self.gender = gender
    }
}
//------------------------------

let human2 = Human(age: 20)
let human3 = Human(age: 40, gender: .male)

We can have more than one initializers based on our requirement, with different parameter names, types. The swift compiler will decide which init method to call based on the argument label. 

Note that it is not possible to call these initializers without using argument labels. Argument labels must always be used in an initializer if they are defined, and omitting them is a compile-time error:

let human4 = Human() // error :cannot invoke initializer for type ‘Human’ with no arguments
let human5 = Human(40,.male) //error:error: missing argument labels 'age:gender:' in call

Default Initialisers :

Swift provides a default initializer for any structure or class that provides default values for all of its properties and does not provide at least one initializer itself.

class ShoppingListItem {
var nameString?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()

Memberwise Initializers for Structure Types :

Structure types automatically receive a memberwise initializer if they do not define any of their own custom initializers. 

struct Size {
var width, height :Double // stored properties without default values
}
-------- or --------------
struct Size {
var width = 10.0, height = 30.0 // stored properties with default values
}

In above both Size struct, there is no any init method defined. Still Size struct can be instantiated by 

let twoByTwo = Size(width: 2.0, height: 2.0)

If we provide custom initialisation, then memberwise initializer instantiation will be failed. See following :  

struct Size {
var width, height :Double
init(){
self.width = 10.0
self.height = 30.0
}
}
let sizeObj1 = Size(width: 2.0, height: 2.0)// error. argument passed to call that takes no arguments
let sizeObj2 = Size() // success.

Initializer Delegation for Value Types :

Initializers can call other initializers to perform part of an instance’s initialization. This process, known as initializer delegation.

struct Size {
 var width = 0.0, height = 0.0
}
struct Point {
 var x = 0.0, y = 0.0
}

struct Rect {
 var origin = Point()
 var size = Size()
 init() {}
 init(origin: Point, size: Size) {
   self.origin = origin
   self.size = size
 }

init(center: Point, size: Size) {
  let originX = center.x - (size.width / 2)
  let originY = center.y - (size.height / 2)
  self.init(origin: Point(x: originX, y: originY), size: size)
 }
}

Designated Initializers and Convenience Initializers :

Swift defines two kinds of initializers for class types to help ensure all stored properties receive an initial value.

Designated initializers
Convenience initializers

Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.
Every class should have at least one designated initializer.

Designated initializers for classes are written in the same way as simple initializers for value types:

Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.

class HumanBeing {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: “not set”)
// Convenience init call the designated init method
}
}
let humanBeingObj1 = HumanBeing() // calls convenience init
let humanBeingObj2 = HumanBeing(name: “abhilash”) // calls designated init


Failable Initializers :

We cannot always assume that the initialization will always succeed for a struct, enum or class. It can fail for several reasons. It is sometimes useful to define a class, structure, or enumeration for which initialization can fail.

You write a failable initializer by placing a question mark after the initkeyword (init?).

You cannot define a failable and a nonfailable initializer with the same parameter types and names.

 In swift, the initializers won’t return anything. But objective -C does. In swift, You write return nil to trigger an initialization failure, you do not use the return keyword to indicate initialization success.

struct Animal {
let species: String
init?(species: String) {
if species.isEmpty { return nil }
self.species = species
}

}

Check :

let someCreature = Animal(species: "Giraffe")
// someCreature is of type Animal?, not Animal
if let giraffe = someCreature {
print("An animal was initialized with a species of \(giraffe.species)")
}

// Prints "An animal was initialized with a species of Giraffe"


Failable Initializers for Enumerations :

You can use a failable initializer to select an appropriate enumeration case based on one or more parameters. The initializer can then fail if the provided parameters do not match an appropriate enumeration case.

enum TemperatureUnit {
case kelvin, celsius, fahrenheit
init?(symbol: Character) {
switch symbol {
case "K":
self = .kelvin
case "C":
self = .celsius
case "F":
self = .fahrenheit
default:
return nil
}
}

guard let fahrenheitUnit = TemperatureUnit(symbol: "X") else {
print("This is not a defined temperature unit, so initialization failed.")
}

// Prints "This is not a defined temperature unit, so initialization failed."

Failable Initializers for Enumerations with Raw Values :

Enumerations with raw values automatically receive a failable initializer, init?(rawValue:), that takes a parameter called rawValue of the appropriate raw-value type and selects a matching enumeration case if one is found, or triggers an initialization failure if no matching value exists.

enum TemperatureUnit: Character {
case kelvin = "K", celsius = "C", fahrenheit = "F"
}
let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
// Prints "This is a defined temperature unit, so initialization succeeded."


Propagation of Initialization Failure :

If your subclass is having a failable initializer which in turn call its superclass failable designated initializer, then if either of the initialization failed means the entire initialization process fails immediately, and no further initialization code is executed.

class Product {
let name: String
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
class CartItem: Product {
let quantity: Int
init?(name: String, quantity: Int) {
if quantity < 1 { return nil }
self.quantity = quantity
super.init(name: name)
}
}

if let zeroShirts = CartItem(name: "shirt", quantity: 0) { // fails
print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")
} else {
print("Unable to initialize zero shirts")
}
// Prints "Unable to initialize zero shirts"

if let oneUnnamed = CartItem(name: "", quantity: 1) { // fails
print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")
} else {
print("Unable to initialize one unnamed product")
}
// Prints "Unable to initialize one unnamed product"


Required Initializers in swift :

Write the required modifier before the definition of a class initializer to indicate that every subclass of the class must implement that initializer.

You must also write the required modifier before every subclass implementation of a required initializer, to indicate that the initializer requirement applies to further subclasses in the chain. You do not write the override modifier when overriding a required designated initializer:

//required init
class classA {
required init() {
var a = 10
print(a)
}
}
class classB: classA {
required init() {
var b = 30
print(b)
}
}
//______________________
let objA = classA()
let objB = classB()
prints:
10
30
10

//______________________

class classC: classA { }
//______________________
let objC = classC() // prints 10 ..superclass init method gets called.


Note: You do not have to provide an explicit implementation of a required initializer if you can satisfy the requirement with an inherited initializer. In the above class classC , since we don’t have any stored properties unintialized at the time of initialization, we dont have to declare the required init explicitly.