Thursday, May 30, 2019

xcode compile error after generating CoreDate NSManagedObject subclass using wizard

In xcode, after generating the subclass of NSManagedObject on a data model, the xcode will get some compile error due to duplicated class name.

This is because xcode will automatically generate a swift class for any CoreDate data model objects added in the project. So once you use the Xcode Editor->Create . NSManagedObject Subclass ... wizard to generate the swift class again, they will have the same class name and cause a compile error.

To avoid the error,
1. first select the xcdatamodeld item, and then select the data model entity.
2. open the data mobel inspector, and change teh Codegen to "Manual/None"
3. Clean and rebuild the project.

 

Thursday, May 16, 2019

Swift: invocation of extension method defined in Protocol calls the static linked method

Polymorphism is a basic feature for object oriented design. Basically, it means when calling a method on an object, no matter the variable type that represents the object (base class, derived sub class, or protocol), the actual method implementation that will be invoked will always be the last override method available in the subclass tree. This is also called dynamic binding, that is why when calling objective c object's method, we never need to cast the object to a particular type, as polymorphism will also end up calling the last override method.

However, unlike objective c, which always uses dynamic binding, Swift uses both dynamic and static binding.

In swift, if a method is defined in protocol, or a class, then all struct, class, or subclass, which implements the protocol or inherits from the class will promise they will abided by the method signature, and may also provide an override implementation. In this aspect, the invocation on methods defined in protocol, or class use dynamic binding as objective c does.

However, things are different when a method is defined in extension for a protocol or class. as extension does not belong to the contract between  base class (or protocol) and sub class, so if same method is provided in a protocol extension and a subclass, the two methods do not have any connections. So in this case, Swift uses static binding for invocation of extension method, and the actual method that will be invoked depends on the variable type at compile time, instead of the actual object type at runtime.

The behavior can be demonstrated with the below code


protocol Movable {
    func move()
}

extension Movable {
    func move() {
       print("move implemented by Movable Protocol extension")
    }
    
    func pause() {
       print("pause implemented by Movable Protocol extension")
    }
}

struct Animal: Movable {
    func move() {
        print("move implemented by Animal structure")
    }
    
    func pause(){
         print("pause implemented by Animal structure")
    }
}

class Car: Movable {
    func move() {
        print("move implemented by Car class")
    }
    
    func pause(){
         print("pause implemented by Car class")
    }
}

extension Car {
    @objc func stop() {
        print("stop implemented by Class extension")
    }
}

class BMW: Car {
    override func move() {
        print("move implemented by BMW class")
    }
    
    override func pause(){
         print("pause implemented by BMW class")
    }
    
    override func stop() {
        print("stop implemented by BMW class")
    }
}


When calling the below code
      let a : Animal = Animal()
        a.move()
        a.pause()
        
        let ap : Movable = a
        ap.move()
        ap.pause()
        
        let c : Car = Car()
        c.move()
        c.pause()
        c.stop()
        
        let cp : Movable = c
        cp.move()
        cp.pause()
        
        
        let b : BMW = BMW()
        b.move()
        b.pause()
        b.stop()
        
        let bc : Car = b
        bc.move()
        bc.pause()
        bc.stop()
        
        let bcp : Movable = bc
        bcp.move()

        bcp.pause()


the output is shown below, and even if the object instance stays the same, the actual method invoked depends on the variable type it casts. The output shows few method calling into Movable protocol's implementation instead of actual Animal, Car or BMW's implementation.


move implemented by Animal structure
pause implemented by Animal structure
move implemented by Animal structure
pause implemented by Movable Protocol extension
move implemented by Car class
pause implemented by Car class
stop implemented by Class extension
move implemented by Car class
pause implemented by Movable Protocol extension
move implemented by BMW class
pause implemented by BMW class
stop implemented by BMW class
move implemented by BMW class
pause implemented by BMW class
stop implemented by BMW class
move implemented by BMW class
pause implemented by Movable Protocol extension


Note, this is an issue only for protocol extension, but not for class extension. As swift will report a compile error if a subclass (or subclass' extension) tries to add a method which has the same signature as defined in base class' extension. In that case, the base class extension method must be defined as @objc, which effectively change it to dynamic binding as objective c does.

Monday, May 13, 2019

Associated Value for Swift Enum type

  1. Usually for simple enum type, it can defined as below. Each enum value can be used as constant definition. For example, if you define enum Barcode { case upc case qrCode } Then in your code, you can set var m = Barcode.upc or check whether a variable equals Barcode.upc or Barcode.grCode in a switch statement. In swift, enum type can also define associated type. When associated type is defined for enum type, then each enum instance must specify the value of the associated types. In this sense, the enum variable with associated type is more like an object with properties. Associated type can be easily accessed from switch statement as shown below enum Barcode { case upc(Int, Int, Int, Int) case qrCode(String) } var productBarcode = Barcode.upc(8, 85909, 51226, 3) var productBarcode2 = .qrCode("ABCDEFGHIJKLMNOP") switch productBarcode { case .upc(let numberSystem, let manufacturer, let product, let check): print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).") case .qrCode(let productCode): print("QR code: \(productCode).") }

Note, in the below code, the type of v and vv are different

        let v = Barcode.upc . //type of v is (Int, Int, Int, Int) -> Barcode
        let vv = Barcode.upc(1, 2, 3, 4) . //type of vv is upc(1, 2, 3, 4)



Optional type is a special usage of enum. In swift, Optional is defined as
enum Optional<Wrapped> {
case none
  case some(Wrapped)
}
nil is just a shortened form of Optional.none.
SomeType? is a shorted form of Optional<SomeType>.
Sometime, it is needed to use the original Optional type to set the nested optional value, such as, setting String??'s value to a String? object whose value is nil as shown below

let s1: String?? = Optional.some(nil)
let s2 :String?? = .none
print(String(describing: s1))
if let s3 = s2 {
    print("s3 is \(String(describing: s3))")
    if let s4 = s3 {
        print("sssnil is \(String(describing: s4))")
    }
    else {
        print("s3's value is nil")
    }
}


Closure and function in swift

In swift, closure and function are same type as they are defined with the same format as below

      var closureargu : (Int, String)->String 

The above variable can be set either to a function by assigning it to a function name, or it can be set to a closure block.

A function is a particular form of closure, which includes the parameter name information, similar as closure's body implementation.

Even if a function has specified argument name, when the function is assigned to a closure variable, invoking the function by the closure variable does not need to specify the argument name as the closure variable only knows the type information without the argument name information. So once a function or closure body is assigned to a closure variable, it does not know whether the body implementation is from a function or closure.

Actually, when function or signaure used as a type, it cannot include argument label information, otherwise xcode will generate a compile error of "Function types cannot have argument labels" error. For example, the below code does not compile as (sumValue : Result, item : Element) -> Result) defines a function type with argument labels in it. 

func reduce<Result>(initial : Result, sum : (sumValue : Result, item : Element) -> Result) -> Result {
        var total = initial
        for it in self {
            total = sum(total, it)
        }
        return total
    }

To fix the compile error, the code should be changed as
func reduce<Result>(initial : Result, sum : (Result, Element) -> Result) -> Result {
        var total = initial
        for it in self {
            total = sum(total, it)
        }
        return total
    }
}


The below sample shows this behavior

var handlerWithParamAndValue : (Int, String) -> String  =  {pi, ps in
        return pi.description + " " + ps

}


func functionSample(a1 a: Int,  b1 b : String) -> String {
        return a.description + b.description
}
    
(Theoretically, the below code should not need @escaping keyword, as closure cannot be called after the function returns. However, without specifying @escaping, a compile error happens in xcode)

func someFunction(_ p1: Int, _ p2: String,  clo: @escaping (Int, String)->String) -> String {

       //assign function to variable
        var closureargu : (Int, String)->String = functionSample
        var re = closureargu(2, "def")
        
        //assign closure variable 
        closureargu = handlerWithParamAndValue
        re = closureargu(3, "mnq")
    
        //assign closure body
        closureargu = {p1, p2 in
           return p1.description + p2.description
        }
        re = closureargu(4, "me")
        
        //assign input closure parameter
        closureargu = clo
        re = clo(p1, p2)
        re = closureargu(p1, p2)
        
        //direct invoke function
        re = functioinSample(a1: 1, b1: "hihi")
        print(re)
        return re
}


//call the testing method
let r = someFunction( 1, "string", clo: {(a1 , a2) in

            let m = a1 + a1
            return a2.description + m.description          
        })


One unique feature to Closure is it allows specifying a capture list  before parameter list to change the self or other caller scope variables to weak or unowned, as shown below
  1. var asHTML: () -> String = {
  2. [unowned self] in
  3. if let text = self.text {
  4. return "<\(self.name)>\(text)</\(self.name)>"
  5. } else {
  6. return "<\(self.name) />"
  7. }
  8. }
Closure can update the value of the captured variables in outer scope, as long as the variable is mutable (defined by var, not by let).

Variable type difference between swift and javascript

Both javascript and swift use the keyword var to define variables, so it may give the impression the variable type works in similar way between swift and javascript.

However, there is a distinct difference between swift and javascript.

For javascript a variable defined by var can change its actual type any time, so when the variable is used in code, the type of the variable depends on the last assignment to the variable, so it may be a int, a string, or a function.
//valid for javascript, but invalid for swift
var i = 5;
i = "string"
i = null;

This is quite different for swift. In swift, from the moment a variable is declared or defined, it will have a particular type associated with it, and the in the whole life time of application running the type of this variable will not change, so whenever the variable is used in the code, we are certain the type of variable will be. As a result, the above code will not compile for Swift, as when i is first set to 5, its variable type is set to integer, and its type can never change, so assigning it to string or null will fail to compile.

Quite often, the confusion about swift variable type comes from type inference, in which case,  swift can infer the type of the variable from the context, so developers do not need to explicitly specify the variable type.

For example, both array and set use the same format to initialize the initial value, so without explicitly specify the variable type, developer may create a Array of string when a Set of string is expected.

        let arrVar = ["abc", "def"]
    let setVar : Set<String> = ["abc", "def"]

Another confusion of swift variable type is using closure. When closuring is used, swift complier can find out all the closure parameter types from dependent library, so it allows developer to skip those type information in the code. However, when people reading the code may not know the signature of the closure being invoked, so it will not give them the enough information when reading the code and understand the logic.

For example,  the following three ways of invocation will not show what input variable types being used in the closure, and when others read the code.


let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
reversedNames = names.sorted(by: >)
reversedNames = names.sorted(by: { $0 > $1 } )
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

While the below code will provide a better description to others about the closure signature being invoked.

     let reversedNames = names.sorted(by: {
          (s1 : String, s2 : String) -> Bool in
             return s1 > s2
     })

In addition, unique to Swift, when a value type is defined by let, the object instance, as well as all its properties cannot be changed. However, when a reference type is defined by let, although the object instance itself cannot be changed to another object instance, its properties can be changed to different values

Wednesday, May 8, 2019

Understanding iOS Dispatch queue and GCD (Grand Centre Dispatch)

Concurrency Mode:
There are two types of dispatch queue in term of concurrency: concurrent queue and serial queue.

For serial queue, the next task gets started only if the previous task is finished, so the tasks are executed sequentially. There should only be one thread for each serial queue, as the next task will not start before the previous task returns.

For concurrent queue, the previous task always starts before the next task, but the next task(s) can start before the previous task returns. As multi tasks run in parallel, so a concurrent queue can create and use multiple threads to executes its tasks.


Queue Creation:
There are three types of dispatch queue in term of queue creation: Main, Global, and custom.

The Main dispatch queue is a globally available serial queue that executes tasks on the application’s main thread, it is only for UI activities, the qos class for main queue is
Dispath.DispatchQoS.QoSClass.userInteractive
The below code can be used to get main queue object
let mainQueue = DispatchQueue.main


The Global dispatch queue are system dispatch concurrent queues, QosClass parameter can be used to specify the priority of the queue.
The below code can be used to get the global queue object

let globalQueue = DispatchQueue.global(qos: .default)


Custom dispatch queue can be created by developers, it can either be serial queue or concurrent queue depending on attribute parameter
//create serial queue
let customSerialQueue = DispatchQueue(label: "my.custom.serial")
//create concurrent queue
let customConcurrentQueue = DispatchQueue(label: "my.custom.concurrent", qos:.default, attributes: .concurrent)


Dispatch task
Sync task
Synced task will block the current caller's thread, until the task returns, so it can have a return value to the caller. 
Note if the current task is running in main or a serial queue, then it cannot invoke another synced task to the same queue, otherwise, the app will crash due to a dead lock. However, it is fine to dispatch a sync task to the same queue if the queue is a concurrent queue (global or custom concurrent queue).

From main thread to execute a sync task on a global or custom queue, will cause the code to be run in the main thread instead of the background thread.

Async task
Asynced task is more common in application implementation. Since the task runs asynchronously so it cannot return any result to the caller.
Note, as mobile device usually only has limited cores for background thread to use, so application should avoid create two many async tasks which blocks for some reason, as once a queue creates 64 threads, the application will hangs. In addition, creating too many threads in CPU intensive operation will only increase the context switch,  and deteriorate the app performance.