Search Your Question

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.

What is entry point of iOS Application?

Ans : 

In mostly language, There is having main method in main file which is starting point of project. In iOS, also same approach are there.

Objective-C :

main.m File :

int main(int argc, char * argv[]) {
        NSString * appDelegateClassName;
        @autoreleasepool {
            // Setup code that might create autoreleased objects goes here.
            appDelegateClassName = NSStringFromClass([AppDelegate class]);
        }
        return UIApplicationMain(argc, argv, nil, appDelegateClassName);
        
        

    }

Swift : 

AppDelegate.swift

import UIKit
import CoreData

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {




In Swift, @UIApplicationMain attribute is a replacement of main.m file & and entry point for your application to start.


Meaning of ??, !!, !?, ?!

Ans : 

1. ?? is  Nil-Coalescing Operator. It is used to provide default value if value is nil.

let val = values["value1"] as? String ?? "default"

2. !!

i.e
struct StockFullData: Codable
{  
           var ok : Bool?  
           var sn : StockName?
}

struct StockName : Codable
{  
           let display_name : String?
}

Now Check :

print(s.sn?.display_name)      
print((s.sn?.display_name!))      
print((s.sn?.display_name!)!)      
 print((s.sn!.display_name!))

Output :

Optional("m")
Optional("m")
m
m

-> See third print, where we have used !! for extract value. I am not sure it is correct answer because it is like !)! .

3. !? : am finding answer or We can make custom operator using this .
4. ?! : am finding answer or We can make custom operator using this .

If you have any comment, question, or recommendation, feel free to post them in the comment section below!


SOLID Principle with Example

Ans : 

S - Single responsibility
O - Open closed
L - Liskov Substitution
I - Interface segregation
D - Dependency Inversion

1. Single Responsibility : Each an every class you create/change should have only one responsibility. We have one class which has many methods having different responsibility. If we add all methods in one class then this class looks monster.

Code for Example :

class ViewClaimDetailController {
    
    func getAllClaimDetail() {
        let jsonData = getDataFromAPI()
        let claims = parseJsonAndFillToArray(data : jsonData)
        saveDataToLocalDB(claims: claims)
       
    }
    
    private func getDataFromAPI(){
        
    }
    
    private func parseJsonAndFillToArray(data : Any) {
        
    }
    
    private func saveDataToLocalDB(claims: [Any]) {
        
    }

}

In our above class, there are 3  private methods having different responsibility. It is very difficult for testing this class and methods as its private.

Solution is to make different classes for different behaviour or responsibilities and make one more class and call above classes methods from this class. So code is readable and also testing can be done easily.

class ViewClaimDetailController {
    
    let netcore = NetCore()
    let conversationFactory = ConversationFactory()
    let coredata = coredataController()
    
    func getAllClaimDetail() {
        let jsonData = netcore.getDataFromAPI()
        let claims = conversationFactory.parseJsonAndFillToArray(data : jsonData)
        coredata.saveDataToLocalDB(claims: claims)
    }
}

class NetCore {
    func getDataFromAPI() {
        // save to coredata
    }
}

class ConversationFactory {
    func parseJsonAndFillToArray(data: Any) {
        // save to coredata
    }
}

class coredataController {
    func saveDataToLocalDB(claims: [Any]) {
        // save to coredata
    }

}


2. Open Closed Principle : Classes and Module should be open for extension and closed for modification. According to this principle, we should write such a class or code that should not be change when new requirement comes.

Code for Example :

class Rectangle {
    var width : Double = 0
    var height : Double = 0
    
    init(inWidth: Double, inHeight: Double) {
        self.width = inWidth
        self.height = inHeight
    }
}

class AreaCalc {
    
    func calculateArea(rectangel: Rectangle) -> Double {
        return rectangel.width  * rectangel.height
    }

}

 If we want to calculate area for new shape, then we have to modify existing calculateArea() method like following :

class AreaCalc {
    
    func calculateArea(shape: AnyObject) -> Double {
        if (shape is Rectangle) {
            return shape.width  * shape.height
        } else if (shape is Square) {
            return shape.width * shape.width
        }
    }

}

Again, if want to add area of circle, triangle, we modify method and expand our if....else if... condition.

This is not good according open-closed principle. According to open-closed principle above code should be like following : 

protocol Shape {
    func calculateArea() -> Double
}

class Rectangle: Shape {
    
    var width : Double = 0
    var height : Double = 0
    
    init(inWidth: Double, inHeight: Double) {
        self.width = inWidth
        self.height = inHeight
    }
    
    internal func calculateArea() -> Double {
        return self.width * self.height
    }
}

class Circle: Shape {
    let radius : Double = 0
   
    internal func calculateArea() -> Double {
        return M_PI * radius * radius
    }
}

class AreaCalc {
    
    func area(shape: Shape) -> Double {
        return shape.calculateArea()
    }
}

We can achieve open-closed principle with help of protocol.

3. Liknov's substitution Principle : New derived classes should extend the base classes without changing the base class behaviour. Subclass should override the parent class methods in a way that doesn't break the functionality of base class from client point of view. 

Code for example : 

We have rectangle class in open-closed principle. Assume there it is not confirming Shape protocol.
Now we make square class

class square : Rectangle {
    
    override var width: Double {
        didSet {
            height = width
        }
    }
    
    override var height: Double {
        didSet {
            width = height
        }
    }
}

Now we write test cases :

func testAreaOfRectang1eFor4X3()
{
    let rectangle: Rectangle = Square()
    rectangle.height = 3
    rectangle.width = 4
    let areaCa1cu1ator = AreaCalc()
    let areaOfRectang1e = areaCa1cu1ator.area(rectang1e: rectangle)
    XCTAssertEqua1(areaOfRectang1e , 12, "Area of Rectangle not matching" )
}

Here, rectangle is of square type finding area of rectangle. As we saw override property of square, we can not lost rectangle (base) class definition and we violate liknov principle of Derived class (Square) breaking the parent class (Rectangle) funtionality of caluculating the area. 

Solution of this is only to make protocol and confirm that. That means, we can conclude that violating Liskov’s Principle violates Open Close Principle as well. 

4. Interface segregation principle : 

This principle solves FAT interface problems of Object Oriented Programming. A interface is called FAT when it has too many methods which contains more information than we really want.

Code for example : 

protocol Gesture {
    func didTap()
    func didDoubleTap()
}

class View1 : Gesture {
    
    func didTap() {
        //required this method
    }
    
    func didDoubleTap() {
        // not required this method
    }
}

class View2 : Gesture {
    
    func didTap() {
        // not required this method
    }
    
    func didDoubleTap() {
        //required this method
    }
}

Here view1 required only didTap() method and view2 require only didDoubleTap() method still both class has to implement both methods. So solution, to make 2 protocol and define each method in in each protocol. Class can confirm multiple protocol to achieve functionality. This is rule of interface seggregation. Or we can use @objc to make optional method.

Example 2 : 

class User {
    
    var firstName : String
    var lastName : String
    var imageURL : String
    
    init(firstName : String, lastName: String, imageURL : String) {
        self.firstName = firstName
        self.lastName = lastName
        self.imageURL = imageURL
    }
}

class UserProfileImageView {
    func loadProfilePhoto(user: User) {
        //load user.imageURL
    }
}


Here in loadProfilePhoto method, User instance is passed so all other information except imageURL are also passed. It is not good.

Solution : Use protocol 

protocol UserProfileViewDetails {
    var imageURL: String { get }
}

class User : UserProfileViewDetails {
    
    var firstName : String
    var lastName : String
    var imageURL : String
    
    init(firstName : String, lastName: String, imageURL : String) {
        self.firstName = firstName
        self.lastName = lastName
        self.imageURL = imageURL
    }
}

class UserProfileImageView {
    func loadProfilePhoto(user: UserProfileViewDetails) {
        //load user.imageURL
    }
}

Now the UserProfileImageView’s loadProfileFor(user:UserProfileViewDetails) which is the client has only the imageURL information with it to display the User Profile Image, which agrees with the Interface Segregation Principle.


5. Dependency Inversion Principle  : High level modules should not depend on low level modules both should depend on Abstractions. 

We have used claim details code in "Single Responsibility Principle" code. There ViewClaimController is tightly coupled with another class called CoreDataController to save data into database. But what will happened when same data should also be saved in File System. 

So Solution : 

Code for Example : 

protocol Database {
    func saveDataToLocalDB(claims : [Any])
}

class ViewClaimDetailController {
    
    let database : Database
    
    init(indatabase: Database) {
        database = indatabase
    }
    
    func getAllClaimDetail() {
        let jsonData = getDataFromAPI()
        let claims = parseJsonAndFillToArray(data : jsonData)
        database.saveDataToLocalDB(claims: claims)
    }
}

class coredataController : Database {
    func saveDataToLocalDB(claims: [Any]) {
        // save to coredata
    }
}

class FileSystemController : Database {
    func saveDataToLocalDB(claims: [Any]) {
        // save to coredata
    }
}



Summary : 
  • Each an every class should have only one responsibility
  • Should not modify the existing class for change requirement, rather extent the class
  • Extending or Inheriting a child/derived class should not break any parent or base class functionality
  • The Interface or class API’s to client should have minimum information required by the client
  • Class A should not depend on Class B or vice versa, both should be losely coupled

If you have any comment, question, or recommendation, feel free to post them in the comment section below!