iOS – How To Solve ARC Strong Reference Cycle In Swift ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, We will learn about How to work Automatic Reference Counting (ARC) in Swift. We will discuss about Strong Reference Cycles problem and solution between Class Instances and for closures in Swift. Memory management is the core concept in any programming language. For more information about Memory Management Concepts, you can explore the below articles :

iOS – Why Is Advanced IOS Memory Management Valuable In Swift ?

A famous quote about learning is :

Education is not the filling of a pot but the lighting of a fire.

So Let’s begin.

Swift uses Automatic Reference Counting (ARC) to track and manage your app’s memory usage. In most cases, this means that memory management “just works” in Swift, and we do not need to think about memory management ourself. ARC automatically frees up the memory used by class instances when those instances are no longer needed.

However, in a few cases ARC requires more information about the relationships between parts of our code in order to manage memory for us. We describes those situations and shows how we enable ARC to manage all of our app’s memory. 

Reference counting applies only to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference.


How To Work ARC ?

Every time we create a new instance of a class, ARC allocates a chunk of memory to store information about that instance. This memory holds information about the type of the instance, together with the values of any stored properties associated with that instance.

Additionally, when an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purposes instead. This ensures that class instances do not take up space in memory when they are no longer needed.

However, if ARC were to deallocate an instance that was still in use, it would no longer be possible to access that instance’s properties, or call that instance’s methods. Indeed, if we tried to access the instance, our app would most likely crash.

To make sure that instances don’t disappear while they are still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists.

To make this possible, whenever we assign a class instance to a property, constant, or variable, that property, constant, or variable makes a strong reference to the instance. The reference is called a “strong” reference because it keeps a firm hold on that instance, and does not allow it to be deallocated for as long as that strong reference remains.

Example :

Here’s an example of how Automatic Reference Counting works. This example starts with a simple class called Person, which defines a stored constant property called name:

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    deinit {
        print("\(name) is being deinitialized")
    }
}

The Person class has an initializer that sets the instance’s name property and prints a message to indicate that initialization is underway. The Person class also has a deinitializer that prints a message when an instance of the class is deallocated.

The next code snippet defines three variables of type Person?, which are used to set up multiple references to a new Person instance in subsequent code snippets. Because these variables are of an optional type (Person?, not Person), they are automatically initialized with a value of nil, and do not currently reference a Person instance.

var reference1: Person?
var reference2: Person?
var reference3: Person?

We can now create a new Person instance and assign it to one of these three variables:

reference1 = Person(name: "John Appleseed")
// Prints "John Appleseed is being initialized"

Note that the message "John Appleseed is being initialized" is printed at the point that we call the Person class’s initializer. This confirms that initialization has taken place.

Because the new Person instance has been assigned to the reference1 variable, there’s now a strong reference from reference1 to the new Person instance. Because there’s at least one strong reference, ARC makes sure that this Person is kept in memory and is not deallocated.

If we assign the same Person instance to two more variables, two more strong references to that instance are established:

reference2 = reference1
reference3 = reference1

There are now three strong references to this single Person instance.

If we break two of these strong references (including the original reference) by assigning nil to two of the variables, a single strong reference remains, and the Person instance is not deallocated:

reference1 = nil
reference2 = nil

ARC does not deallocate the Person instance until the third and final strong reference is broken, at which point it’s clear that you are no longer using the Person instance:

reference3 = nil
// Prints "John Appleseed is being deinitialized"


How To Cause Strong Reference Cycles Between Class Instances ?

In the examples above, ARC is able to track the number of references to the new Person instance we create and to deallocate that Person instance when it’s no longer needed.

However, it’s possible to write code in which an instance of a class never gets to a point where it has zero strong references. This can happen if two class instances hold a strong reference to each other, such that each instance keeps the other alive. This is known as a Strong Reference Cycle.

We resolve strong reference cycles by defining some of the relationships between classes as weak or unowned references instead of as strong references. However, before we learn how to resolve a strong reference cycle, it’s useful to understand how such a cycle is caused.

Here’s an example of how a strong reference cycle can be created by accident. This example defines two classes called Person and Apartment, which model a block of apartments and its residents:

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

Every Person instance has a name property of type String and an optional apartment property that is initially nil. The apartment property is optional, because a person may not always have an apartment.

Similarly, every Apartment instance has a unit property of type String and has an optional tenant property that is initially nil. The tenant property is optional because an apartment may not always have a tenant.

Both of these classes also define a deinitializer, which prints the fact that an instance of that class is being deinitialized. This enables us to see whether instances of Person and Apartment are being deallocated as expected.

This next code snippet defines two variables of optional type called john and unit4A, which will be set to a specific Apartment and Person instance below. Both of these variables have an initial value of nil, by virtue of being optional:

var john: Person?
var unit4A: Apartment?

We can now create a specific Person instance and Apartment instance and assign these new instances to the john and unit4A variables:

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

Here’s how the strong references look after creating and assigning these two instances. The john variable now has a strong reference to the new Person instance, and the unit4A variable has a strong reference to the new Apartment instance:

We can now link the two instances together so that the person has an apartment, and the apartment has a tenant. Note that an exclamation point (!) is used to unwrap and access the instances stored inside the john and unit4A optional variables, so that the properties of those instances can be set:

john!.apartment = unit4A
unit4A!.tenant = john

Here’s how the strong references look after we link the two instances together:

Unfortunately, linking these two instances creates a strong reference cycle between them. The Person instance now has a strong reference to the Apartment instance, and the Apartment instance has a strong reference to the Person instance. Therefore, when you break the strong references held by the john and unit4A variables, the reference counts do not drop to zero, and the instances are not deallocated by ARC:

john = nil
unit4A = nil

Note that neither deinitializer was called when we set these two variables to nil. The strong reference cycle prevents the Person and Apartment instances from ever being deallocated, causing a memory leak in your app.

Here’s how the strong references look after we set the john and unit4A variables to nil:

The strong references between the Person instance and the Apartment instance remain and cannot be broken.


How To Solve Strong Reference Cycles Between Class Instances ?

Swift provides two ways to resolve strong reference cycles when we work with properties of class type: weak references and unowned references.

Weak and unowned references enable one instance in a reference cycle to refer to the other instance without keeping a strong hold on it. The instances can then refer to each other without creating a strong reference cycle.

Use a weak reference when the other instance has a shorter lifetime—that is, when the other instance can be deallocated first. In the Apartment example above, it’s appropriate for an apartment to be able to have no tenant at some point in its lifetime, and so a weak reference is an appropriate way to break the reference cycle in this case. In contrast, use an unowned reference when the other instance has the same lifetime or a longer lifetime.


Weak References

weak reference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance. This behavior prevents the reference from becoming part of a strong reference cycle. We indicate a weak reference by placing the weak keyword before a property or variable declaration.

Because a weak reference does not keep a strong hold on the instance it refers to, it’s possible for that instance to be deallocated while the weak reference is still referring to it. Therefore, ARC automatically sets a weak reference to nil when the instance that it refers to is deallocated. And, because weak references need to allow their value to be changed to nil at runtime, they are always declared as variables, rather than constants, of an optional type.

We can check for the existence of a value in the weak reference, just like any other optional value, and you will never end up with a reference to an invalid instance that no longer exists.

“Property observers aren’t called when ARC sets a weak reference to nil.”

The example below is identical to the Person and Apartment example from above, with one important difference. This time around, the Apartment type’s tenant property is declared as a weak reference:

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

The strong references from the two variables (john and unit4A) and the links between the two instances are created as before:

var john: Person?
var unit4A: Apartment?

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

Here’s how the references look now that you’ve linked the two instances together:

The Person instance still has a strong reference to the Apartment instance, but the Apartment instance now has a weak reference to the Person instance. This means that when we break the strong reference held by the john variable by setting it to nil, there are no more strong references to the Person instance:

john = nil
// Prints "John Appleseed is being deinitialized"

Because there are no more strong references to the Person instance, it’s deallocated and the tenant property is set to nil:

The only remaining strong reference to the Apartment instance is from the unit4A variable. If we break that strong reference, there are no more strong references to the Apartment instance:

unit4A = nil
// Prints "Apartment 4A is being deinitialized"

Because there are no more strong references to the Apartment instance, it too is deallocated:

“In systems that use garbage collection, weak pointers are sometimes used to implement a simple caching mechanism because objects with no strong references are deallocated only when memory pressure triggers garbage collection. However, with ARC, values are deallocated as soon as their last strong reference is removed, making weak references unsuitable for such a purpose.”


Unowned References

Like a weak reference, an unowned reference does not keep a strong hold on the instance it refers to. Unlike a weak reference, however, an unowned reference is used when the other instance has the same lifetime or a longer lifetime. We indicate an unowned reference by placing the unowned keyword before a property or variable declaration.

Unlike a weak reference, an unowned reference is expected to always have a value. As a result, marking a value as unowned doesn’t make it optional, and ARC never sets an unowned reference’s value to nil.

Use an unowned reference only when you are sure that the reference always refers to an instance that has not been deallocated. If we try to access the value of an unowned reference after that instance has been deallocated, we’ll get a runtime error.

The following example defines two classes, Customer and CreditCard, which model a bank customer and a possible credit card for that customer. These two classes each store an instance of the other class as a property. This relationship has the potential to create a strong reference cycle.

The relationship between Customer and CreditCard is slightly different from the relationship between Apartment and Person seen in the weak reference example above. In this data model, a customer may or may not have a credit card, but a credit card will always be associated with a customer. A CreditCard instance never outlives the Customer that it refers to. To represent this, the Customer class has an optional card property, but the CreditCard class has an unowned (and non-optional) customer property.

Furthermore, a new CreditCard instance can only be created by passing a number value and a customer instance to a custom CreditCard initializer. This ensures that a CreditCard instance always has a customer instance associated with it when the CreditCard instance is created.

Because a credit card will always have a customer, we define its customer property as an unowned reference, to avoid a strong reference cycle:

class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) {
        self.name = name
    }
    deinit { print("\(name) is being deinitialized") }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("Card #\(number) is being deinitialized") }
}

“The number property of the CreditCard class is defined with a type of UInt64 rather than Int, to ensure that the number property’s capacity is large enough to store a 16-digit card number on both 32-bit and 64-bit systems.”

This next code snippet defines an optional Customer variable called john, which will be used to store a reference to a specific customer. This variable has an initial value of nil, by virtue of being optional:

var john: Customer?

We can now create a Customer instance, and use it to initialize and assign a new CreditCard instance as that customer’s card property:

john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

Here’s how the references look, now that we’ve linked the two instances:

The Customer instance now has a strong reference to the CreditCard instance, and the CreditCard instance has an unowned reference to the Customer instance.

Because of the unowned customer reference, when we break the strong reference held by the john variable, there are no more strong references to the Customer instance:

Because there are no more strong references to the Customer instance, it’s deallocated. After this happens, there are no more strong references to the CreditCard instance, and it too is deallocated:

john = nil
// Prints "John Appleseed is being deinitialized"
// Prints "Card #1234567890123456 is being deinitialized"

The final code snippet above shows that the deinitializers for the Customer instance and CreditCard instance both print their “deinitialized” messages after the john variable is set to nil.

“The examples above show how to use safe unowned references. Swift also provides unsafe unowned references for cases where you need to disable runtime safety checks—for example, for performance reasons. As with all unsafe operations, we take on the responsibility for checking that code for safety. We indicate an unsafe unowned reference by writing unowned(unsafe). If we try to access an unsafe unowned reference after the instance that it refers to is deallocated, our program will try to access the memory location where the instance used to be, which is an unsafe operation.”


Unowned Optional References

We can mark an optional reference to a class as unowned. In terms of the ARC ownership model, an unowned optional reference and a weak reference can both be used in the same contexts. The difference is that when we use an unowned optional reference, we’re responsible for making sure it always refers to a valid object or is set to nil.

Here’s an example that keeps track of the courses offered by a particular department at a school:

class Department {
    var name: String
    var courses: [Course]
    init(name: String) {
        self.name = name
        self.courses = []
    }
}

class Course {
    var name: String
    unowned var department: Department
    unowned var nextCourse: Course?
    init(name: String, in department: Department) {
        self.name = name
        self.department = department
        self.nextCourse = nil
    }
}

Department maintains a strong reference to each course that the department offers. In the ARC ownership model, a department owns its courses. Course has two unowned references, one to the department and one to the next course a student should take; a course doesn’t own either of these objects. Every course is part of some department so the department property isn’t an optional. However, because some courses don’t have a recommended follow-on course, the nextCourse property is an optional. Here’s an example of using these classes:

let department = Department(name: "Horticulture")

let intro = Course(name: "Survey of Plants", in: department)
let intermediate = Course(name: "Growing Common Herbs", in: department)
let advanced = Course(name: "Caring for Tropical Plants", in: department)

intro.nextCourse = intermediate
intermediate.nextCourse = advanced
department.courses = [intro, intermediate, advanced]

The code above creates a department and its three courses. The intro and intermediate courses both have a suggested next course stored in their nextCourse property, which maintains an unowned optional reference to the course a student should take after after completing this one.

An unowned optional reference doesn’t keep a strong hold on the instance of the class that it wraps, and so it doesn’t prevent ARC from deallocating the instance. It behaves the same as an unowned reference does under ARC, except that an unowned optional reference can be nil.

Like non-optional unowned references, we’re responsible for ensuring that nextCourse always refers to a course that hasn’t been deallocated. In this case, for example, when we delete a course from department.courses we also need to remove any references to it that other courses might have.

” The underlying type of an optional value is Optional, which is an enumeration in the Swift standard library. However, optionals are an exception to the rule that value types can’t be marked with unowned. The optional that wraps the class doesn’t use reference counting, so we don’t need to maintain a strong reference to the optional.”


Unowned References and Implicitly Unwrapped Optional Properties

The examples for weak and unowned references above cover two of the more common scenarios in which it’s necessary to break a strong reference cycle.

However, there’s a scenario, in which both properties should always have a value, and neither property should ever be nil once initialization is complete. In this scenario, it’s useful to combine an unowned property on one class with an implicitly unwrapped optional property on the other class.

This enables both properties to be accessed directly (without optional unwrapping) once initialization is complete, while still avoiding a reference cycle. This section shows you how to set up such a relationship.

The example below defines two classes, Country and City, each of which stores an instance of the other class as a property. In this data model, every country must always have a capital city, and every city must always belong to a country. To represent this, the Country class has a capitalCity property, and the City class has a country property:

class Country {
    let name: String
    var capitalCity: City!
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
    }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

To set up the interdependency between the two classes, the initializer for City takes a Country instance, and stores this instance in its country property.

The initializer for City is called from within the initializer for Country. However, the initializer for Country cannot pass self to the City initializer until a new Country instance is fully initialized, 

To cope with this requirement, we declare the capitalCity property of Country as an implicitly unwrapped optional property, indicated by the exclamation point at the end of its type annotation (City!). This means that the capitalCity property has a default value of nil, like any other optional, but can be accessed without the need to unwrap its value.

Because capitalCity has a default nil value, a new Country instance is considered fully initialized as soon as the Country instance sets its name property within its initializer. This means that the Country initializer can start to reference and pass around the implicit self property as soon as the name property is set. The Country initializer can therefore pass self as one of the parameters for the City initializer when the Country initializer is setting its own capitalCity property.

All of this means that we can create the Country and City instances in a single statement, without creating a strong reference cycle, and the capitalCity property can be accessed directly, without needing to use an exclamation point to unwrap its optional value:

var country = Country(name: "Canada", capitalName: "Ottawa")
print("\(country.name)'s capital city is called \(country.capitalCity.name)")
// Prints "Canada's capital city is called Ottawa"

In the example above, the use of an implicitly unwrapped optional means that all of the two-phase class initializer requirements are satisfied. The capitalCity property can be used and accessed like a non-optional value once initialization is complete, while still avoiding a strong reference cycle.


How To Cause Strong Reference Cycles for Closures ?

A strong reference cycle can also occur if we assign a closure to a property of a class instance, and the body of that closure captures the instance. This capture might occur because the closure’s body accesses a property of the instance, such as self.someProperty, or because the closure calls a method on the instance, such as self.someMethod(). In either case, these accesses cause the closure to “capture” self, creating a strong reference cycle.

This strong reference cycle occurs because closures, like classes, are reference types. When we assign a closure to a property, we are assigning a reference to that closure. In essence, it’s the same problem as above—two strong references are keeping each other alive. However, rather than two class instances, this time it’s a class instance and a closure that are keeping each other alive.

Swift provides an elegant solution to this problem, known as a closure capture list. However, before we learn how to break a strong reference cycle with a closure capture list, it’s useful to understand how such a cycle can be caused.

The example below shows how we can create a strong reference cycle when using a closure that references self. This example defines a class called HTMLElement, which provides a simple model for an individual element within an HTML document:

class HTMLElement {

    let name: String
    let text: String?

    lazy var asHTML: () -> String = {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) is being deinitialized")
    }

}

The HTMLElement class defines a name property, which indicates the name of the element, such as "h1" for a heading element, "p" for a paragraph element, or "br" for a line break element. HTMLElement also defines an optional text property, which we can set to a string that represents the text to be rendered within that HTML element.

In addition to these two simple properties, the HTMLElement class defines a lazy property called asHTML. This property references a closure that combines name and text into an HTML string fragment. The asHTML property is of type () -> String, or “a function that takes no parameters, and returns a String value”.

By default, the asHTML property is assigned a closure that returns a string representation of an HTML tag. This tag contains the optional text value if it exists, or no text content if text does not exist. For a paragraph element, the closure would return "<p>some text</p>" or "<p />", depending on whether the text property equals "some text" or nil.

The asHTML property is named and used somewhat like an instance method. However, because asHTML is a closure property rather than an instance method, we can replace the default value of the asHTML property with a custom closure, if we want to change the HTML rendering for a particular HTML element.

For example, the asHTML property could be set to a closure that defaults to some text if the text property is nil, in order to prevent the representation from returning an empty HTML tag:

let heading = HTMLElement(name: "h1")
let defaultText = "some default text"
heading.asHTML = {
    return "<\(heading.name)>\(heading.text ?? defaultText)</\(heading.name)>"
}
print(heading.asHTML())
// Prints "<h1>some default text</h1>"

” The asHTML property is declared as a lazy property, because it’s only needed if and when the element actually needs to be rendered as a string value for some HTML output target. The fact that asHTML is a lazy property means that you can refer to self within the default closure, because the lazy property will not be accessed until after initialization has been completed and self is known to exist.”

The HTMLElement class provides a single initializer, which takes a name argument and (if desired) a text argument to initialize a new element. The class also defines a deinitializer, which prints a message to show when an HTMLElement instance is deallocated.

Here’s how you use the HTMLElement class to create and print a new instance:

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
// Prints "<p>hello, world</p>"

” The paragraph variable above is defined as an optional HTMLElement, so that it can be set to nil below to demonstrate the presence of a strong reference cycle.”

Unfortunately, the HTMLElement class, as written above, creates a strong reference cycle between an HTMLElement instance and the closure used for its default asHTML value. Here’s how the cycle looks:

The instance’s asHTML property holds a strong reference to its closure. However, because the closure refers to self within its body (as a way to reference self.name and self.text), the closure captures self, which means that it holds a strong reference back to the HTMLElement instance. A strong reference cycle is created between the two. 

” Even though the closure refers to self multiple times, it only captures one strong reference to the HTMLElement instance.”

If we set the paragraph variable to nil and break its strong reference to the HTMLElement instance, neither the HTMLElement instance nor its closure are deallocated, because of the strong reference cycle:

paragraph = nil

Note that the message in the HTMLElement deinitializer is not printed, which shows that the HTMLElement instance is not deallocated.


How To Resolve Strong Reference Cycles for Closures ?

We resolve a strong reference cycle between a closure and a class instance by defining a capture list as part of the closure’s definition. A capture list defines the rules to use when capturing one or more reference types within the closure’s body. As with strong reference cycles between two class instances, we declare each captured reference to be a weak or unowned reference rather than a strong reference. The appropriate choice of weak or unowned depends on the relationships between the different parts of our code.

” Swift requires us to write self.someProperty or self.someMethod() (rather than just someProperty or someMethod()) whenever we refer to a member of self within a closure. This helps us remember that it’s possible to capture self by accident.”


Defining a Capture List

Each item in a capture list is a pairing of the weak or unowned keyword with a reference to a class instance (such as self) or a variable initialized with some value (such as delegate = self.delegate). These pairings are written within a pair of square braces, separated by commas.

Place the capture list before a closure’s parameter list and return type if they are provided:

lazy var someClosure = {
    [unowned self, weak delegate = self.delegate]
    (index: Int, stringToProcess: String) -> String in
    // closure body goes here
}

If a closure does not specify a parameter list or return type because they can be inferred from context, place the capture list at the very start of the closure, followed by the in keyword:

lazy var someClosure = {
    [unowned self, weak delegate = self.delegate] in
    // closure body goes here
}


Weak and Unowned References

Define a capture in a closure as an unowned reference when the closure and the instance it captures will always refer to each other, and will always be deallocated at the same time.

Conversely, define a capture as a weak reference when the captured reference may become nil at some point in the future. Weak references are always of an optional type, and automatically become nil when the instance they reference is deallocated. This enables you to check for their existence within the closure’s body.

” If the captured reference will never become nil, it should always be captured as an unowned reference, rather than a weak reference.”

An unowned reference is the appropriate capture method to use to resolve the strong reference cycle in the HTMLElement example from Strong Reference Cycles for Closures above. Here’s how we write the HTMLElement class to avoid the cycle:

class HTMLElement {

    let name: String
    let text: String?

    lazy var asHTML: () -> String = {
        [unowned self] in
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) is being deinitialized")
    }

}

This implementation of HTMLElement is identical to the previous implementation, apart from the addition of a capture list within the asHTML closure. In this case, the capture list is [unowned self], which means “capture self as an unowned reference rather than a strong reference”.

We can create and print an HTMLElement instance as before:

var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
// Prints "<p>hello, world</p>"

Here’s how the references look with the capture list in place:

This time, the capture of self by the closure is an unowned reference, and does not keep a strong hold on the HTMLElement instance it has captured. If you set the strong reference from the paragraph variable to nil, the HTMLElement instance is deallocated, as can be seen from the printing of its deinitializer message in the example below:

paragraph = nil
// Prints "p is being deinitialized"

That’s all about in this article.


Conclusion

In this article, We understood that How to work Automatic Reference Counting (ARC) in Swift. We also discussed about Strong Reference Cycles problem and solution between Class Instances and for closures in Swift. We saw how a strong reference cycle can be created when two class instance properties hold a strong reference to each other, and how to use weak and unowned references to break these strong reference cycles.

We understood Strong Reference Cycles with different scenarios below :

  • The Person and Apartment example shows a situation where two properties, both of which are allowed to be nil, have the potential to cause a strong reference cycle. This scenario is best resolved with a weak reference.
  • The Customer and CreditCard example shows a situation where one property that is allowed to be nil and another property that cannot be nil have the potential to cause a strong reference cycle. This scenario is best resolved with an unowned reference.
  • In a third scenario, in which both properties should always have a value, and neither property should ever be nil once initialization is complete. In this scenario, it’s useful to combine an unowned property on one class with an implicitly unwrapped optional property on the other class.
  • A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of that closure captures the instance. Swift provides an elegant solution to this problem, known as a closure capture list.

Thanks for reading ! I hope you enjoyed and learned about the Automatic Reference Counting (ARC) and Strong Reference Cycles problem and solutions with different scenarios in Swift. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

iOS – Why Is Advanced IOS Memory Management Valuable In Swift ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, We will learn about what’s beyond the basics of iOS memory management, reference counting and object life cycle. Memory management is the core concept in any programming language. Memory management in iOS was initially non-ARC (Automatic Reference Counting), where we have to retain and release the objects. Now, it supports ARC and we don’t have to retain and release the objects. Xcode takes care of the job automatically in compile time. We will explain Memory management in swift from the compiler perspective. We will discuss the fundamentals and gradually make our way to the internals of ARC and Swift Runtime, answering below questions:

  • What is Memory Management?
  • What is Memory Management Issues?
  • What is Memory Management Rules ?
  • How Swift compiler implements Automatic Reference Counting?
  • How ARC Works ?
  • How to handle Memory in ARC ?
  • How strong, weak and unowned references are implemented?
  • What is Swift Runtime ?
  • What are Side Tables?
  • What is the life cycle of Swift objects?
  • What is Reference Count Invariants during Swift object lifecycle ?

A famous quote about learning is :

An investment in knowledge pays the best interest.”

So, Let’s begin.


What is Memory Management ?

At hardware level, memory is just a long list of bytes. We organized into three virtual parts:

  • Stack, where all local variables go.
  • Global data, where static variables, constants and type metadata go.
  • Heap, where all dynamically allocated objects go. Basically, everything that has a lifetime is stored here.

We’ll continue saying ‘objects’ and ‘dynamically allocated objects’ interchangeably. These are Swift reference types and some special cases of value types.

So We can define Memory Management :

Memory Management is the process of controlling program’s memory. It is critical to understand how it works, otherwise you are likely to run across random crashes and subtle bugs.”


What is Memory Management Issues?

As per Apple documentation, the two major issues in memory management are:

  • Freeing or overwriting data that is still in use. It causes memory corruption and typically results in your application crashing, or worse, corrupted user data.
  • Not freeing data that is no longer in use causes memory leaks. When allocated memory is not freed even though it is never going to be used again, it is known as memory leak. Leaks cause your application to use ever-increasing amounts of memory, which in turn may result in poor system performance or (in iOS) your application being terminated.


What is Memory Management Rules ?

Memory Management Rules are :

  • We own the objects we create, and we have to subsequently release them when they are no longer needed.
  • Use Retain to gain ownership of an object that you did not create. You have to release these objects too when they are not needed.
  • Don’t release the objects that you don’t own.


How Swift compiler implements automatic reference counting?

Memory management is tightly connected with the concept of OwnershipOwnership is the responsibility of some piece of code to eventually cause an object to be destroyed. Any language with a concept of destruction has a concept of ownership. In some languages, like C and non-ARC Objective-C, ownership is managed explicitly by programmers. In other languages, like C++ (in part), ownership is managed by the language. Even languages with implicit memory management still have libraries with concepts of ownership, because there are other program resources besides memory, and it is important to understand what code has the responsibility to release those resources.

Swift already has an ownership system, but it’s “under the covers”: it’s an implementation detail that programmers have little ability to influence.

Automatic reference counting (ARC) is Swift ownership system, which implicitly imposes a set of conventions for managing and transferring ownership.

Swift uses Automatic Reference Counting (ARC) to track and manage your app’s memory usage. In most cases, this means that memory management “just works” in Swift, and you do not need to think about memory management yourself. ARC automatically frees up the memory used by class instances when those instances are no longer needed.

However, in a few cases ARC requires more information about the relationships between parts of your code in order to manage memory for you.

The name by which an object can be pointed is called a reference. Swift references have two levels of strength: strong and weak. Additionally, weak references have a flavour, called unowned.

The essence of Swift memory management is: Swift preserves an object if it is strongly referenced and deallocates it otherwise. The rest is just an implementation detail.”


How ARC Works ?

Every time you create a new instance of a class, ARC allocates a chunk of memory to store information about that instance. This memory holds information about the type of the instance, together with the values of any stored properties associated with that instance.

Additionally, when an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purposes instead. This ensures that class instances do not take up space in memory when they are no longer needed.

However, if ARC were to deallocate an instance that was still in use, it would no longer be possible to access that instance’s properties, or call that instance’s methods. Indeed, if you tried to access the instance, your app would most likely crash.

To make sure that instances don’t disappear while they are still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists.

To make this possible, whenever you assign a class instance to a property, constant, or variable, that property, constant, or variable makes a strong reference to the instance. The reference is called a “strong” reference because it keeps a firm hold on that instance, and does not allow it to be deallocated for as long as that strong reference remains.

Example :

Here’s an example of how Automatic Reference Counting works. This example starts with a simple class called Person, which defines a stored constant property called name:

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    deinit {
        print("\(name) is being deinitialized")
    }
}

The Person class has an initializer that sets the instance’s name property and prints a message to indicate that initialization is underway. The Person class also has a deinitializer that prints a message when an instance of the class is deallocated.

The next code snippet defines three variables of type Person?, which are used to set up multiple references to a new Person instance in subsequent code snippets. Because these variables are of an optional type (Person?, not Person), they are automatically initialized with a value of nil, and do not currently reference a Person instance.

var reference1: Person?
var reference2: Person?
var reference3: Person?

You can now create a new Person instance and assign it to one of these three variables:

reference1 = Person(name: "John Appleseed")
// Prints "John Appleseed is being initialized"

Note that the message "John Appleseed is being initialized" is printed at the point that you call the Person class’s initializer. This confirms that initialization has taken place.

Because the new Person instance has been assigned to the reference1 variable, there is now a strong reference from reference1 to the new Person instance. Because there is at least one strong reference, ARC makes sure that this Person is kept in memory and is not deallocated.

If you assign the same Person instance to two more variables, two more strong references to that instance are established:

reference2 = reference1
reference3 = reference1

There are now three strong references to this single Person instance.

If you break two of these strong references (including the original reference) by assigning nil to two of the variables, a single strong reference remains, and the Person instance is not deallocated:

reference1 = nil
reference2 = nil

ARC does not deallocate the Person instance until the third and final strong reference is broken, at which point it’s clear that you are no longer using the Person instance:

reference3 = nil
// Prints "John Appleseed is being deinitialized"


How to handle Memory in ARC ?

You don’t need to use release and retain in ARC. So, all the view controller’s objects will be released when the view controller is removed. Similarly, any object’s sub-objects will be released when they are released. Note that if other classes have a strong reference to an object of a class, then the whole class won’t be released. So, it is recommended to use weak properties for delegates.


How strong, weak and unowned references are implemented?

The purpose of a strong reference is to keep an object alive. Strong referencing might result in several non-trivial problems.

  • Retain cycles. Considering that Swift language is not cycle-collecting, a reference R to an object which holds a strong reference to the object R (possibly indirectly), results in a reference cycle. We must write lots of boilerplate code to explicitly break the cycle.
  • It is not always possible to make strong references valid immediately on object construction, e.g. with delegates.

Weak references address the problem of back references. An object can be destroyed if there are weak references pointing to it. A weak reference returns nil, when an object it points to is no longer alive. This is called zeroing.

Unowned references are different flavor of weak, designed for tight validity invariants. Unowned references are non-zeroing. When trying to read a non-existent object by an unowned reference, a program will crash with assertion error. They are useful to track down and fix consistency bugs.


What is Swift Runtime ?

The mechanism of ARC is implemented in a library called Swift Runtime. It implements such core features as the runtime type system, including dynamic casting, generics, and protocol conformance registration.

Swift Runtime represents every dynamically allocated object with HeapObject struct. It contains all the pieces of data which make up an object in Swift: reference counts and type metadata.

Internally every Swift object has three reference counts: one for each kind of reference. At the SIL generation phase, swiftc compiler inserts calls to the methods swift_retain() and swift_release(), wherever it’s appropriate. This is done by intercepting initialization and destruction of HeapObjects.

Compilation is one of the steps of Xcode Build System.


What are Side Tables?

Side Tables are mechanism for implementing Swift weak references.

Typically objects don’t have any weak references, hence it is wasteful to reserve space for weak reference count in every object. This information is stored externally in side tables, so that it can be allocated only when it’s really needed.

Instead of directly pointing to an object, weak reference points to the side table, which in its turn points to the object. This solves two problems:

  • saves memory for weak reference count, until an object really needs it.
  • allows to safely zero out weak reference, since it does not directly point to an object, and no longer a subject to race conditions.

Side table is just a reference count + a pointer to an object. They are declared in Swift Runtime as follows (C++ code).

class HeapObjectSideTableEntry {
  std::atomic<HeapObject*> object;
  SideTableRefCounts refCounts;
  // Operations to increment and decrement reference counts
}


What is the life cycle of Swift objects?

Swift objects have their own life cycle, represented by a finite state machine on the figure below. Square brackets indicate a condition that triggers transition from state to state. We will discuss the finite state machines in Eliminating Degenerate View Controller States.

In live state an object is alive. Its reference counts are initialized to 1 strong, 1 unowned and 1 weak (side table starts at +1). Strong and unowned reference access work normally. Once there is a weak reference to the object, the side table is created. The weak reference points to the side table instead of the object.

From the live state, the object moves into the deiniting state once strong reference count reaches zero. The deiniting state means that deinit() is in progress. At this point strong ref operations have no effect. Weak reference reads return nil, if there is an associated side table (otherwise there are no weak refs). Unowned reads trigger assertion failure. New unowned references can still be stored. From this state, the object can take two routes:

  • A shortcut in case there no weak, unowned references and the side table. The object transitions to the dead state and is removed from memory immediately.
  • Otherwise, the object moves to deinited state.

In the deinited state deinit() has been completed and the object has outstanding unowned references (at least the initial +1). Strong and weak stores and reads cannot happen at this point. Unowned stores also cannot happen. Unowned reads trigger assertion error. The object can take two routes from here:

  • In case there are no weak references, the object can be deallocated immediately. It transitions into the dead state.
  • Otherwise, there is still a side table to be removed and the object moves into the freed state.

In the freed state the object is fully deallocated, but its side table is still alive. During this phase the weak reference count reaches zero and the side table is destroyed. The object transitions into its final state.

In the dead state there is nothing left from the object, except for the pointer to it. The pointer to the HeapObject is freed from the Heap, leaving no traces of the object in memory.


What is Reference Count Invariants during Swift object lifecycle ?

During their life cycle, the objects maintain following invariants:

  • When the strong reference count becomes zero, the object is deinitedUnowned reference reads raise assertion errors, weak reference reads become nil.
  • The unowned reference count adds +1 to the strong one, which is decremented after object’s deinit completes.
  • The weak reference count adds +1 to the unowned reference count. It is decremented after the object is freed from memory.


Conclusion

In this article, We understood about Advanced iOS Memory management in Swift. Automatic reference counting is no magic and the better we understand how it works internally, the less our code is prone to memory management errors. Here are the key points to remember:

  • Weak references point to side a table. Unowned and strong references point to an object.
  • Automatic referencing count is implemented on the compiler level. The swiftc compiler inserts calls to release and retain wherever appropriate.
  • Swift objects are not destroyed immediately. Instead, they undergo 5 phases in their life cycle: live -> deiniting -> deinited -> freed -> dead.

Thanks for reading ! I hope you enjoyed and learned about the Advanced memory management concepts in Swift. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

iOS – Is Awesome Design Pattern Valuable In Swift ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, We will learn about Why design patterns are important and which one is the most popular frequently used design patterns in Swift. Swift is a programming language that allows developers to create versatile applications for multiple operating systems (though it is most frequently used to write applications for iOS). When we are new in programming languages, we don’t know which design patterns we should use with it and how to implement them.

Being able to use a relevant design pattern is a prerequisite to creating functional, high-quality, and secure applications. 

We’ve decided to help by taking an in-depth look at the design patterns most widely used in Swift and showing different approaches to solving common problems in mobile development with them.

A famous quote about learning is :

“ Anyone who stops learning is old, whether at twenty or eighty. Anyone who keeps learning stays young. ” 


So Let’s begin.


Design Patterns: What they are and why you should know them ?

A software design pattern is a solution to a particular problem you might face when designing an app’s architecture. But unlike out-of-the-box services or open-source libraries, we can’t simply paste a design pattern into our application because it isn’t a piece of code. Rather, it’s a general concept for how to solve a problem. A design pattern is a template that tells you how to write code, but it’s up to you to fit our code to this template.

Design patterns bring several benefits:

  • Tested solutions. We don’t need to waste time and reinvent the wheel trying to solve a particular software development problem, as design patterns already provide the best solution and tell us how to implement it.
  • Code unification. Design patterns provide us with typical solutions that have been tested for drawbacks and bugs, helping us make fewer mistakes when designing our app architecture.
  • Common vocabulary. Instead of providing in-depth explanations of how to solve this or that software development problem, we can simply say what design pattern we used and other developers will immediately understand what solutions we implemented.


Types of Software Design Patterns

Before we describe the most common architecture patterns in Swift, you should first learn the three types of software design patterns and how they differ:

  • Creational Design Patterns
  • Structural Design Patterns
  • Behavioral Design Patterns


1. Creational Design Patterns

Creational software design patterns deal with object creation mechanisms, which increase flexibility and reuse of existing code. They try to instantiate objects in a manner suitable for the particular situation. Here are several creational design patterns:

  • Factory Method
  • Abstract Factory
  • Builder
  • Singleton
  • Prototype


2. Structural Design Patterns

Structural design patterns aim to simplify the design by finding an easy way of realizing relationships between classes and objects. These patterns explain how to assemble objects and classes into larger structures while keeping these structures flexible and efficient.These are some structural architecture patterns:

  • Adapter
  • Bridge
  • Facade
  • Decorator
  • Composite
  • Flyweight
  • Proxy


3. Behavioral Design Patterns

Behaviour design patterns identify common communication patterns between entities and implement these patterns. 

These patterns are concerned with algorithms and the assignment of responsibilities between objects. Behavioral design patterns include:

  • Chain of Responsibility
  • Template Method
  • Command
  • Iterator
  • Mediator
  • Memento
  • Observer
  • Strategy
  • State
  • Visitor

Most of these design patterns, however, are rarely used, and you’re likely to forget how they work before you even need them. So we’ve handpicked the five design patterns most frequently used in Swift to develop applications for iOS and other operating systems.


Most frequently used design patterns in Swift

We’re going to provide only the essential information about each software design pattern – namely, how it works from the technical point of view and when it should be applied. We’ll also give an illustrative example in the Swift programming language.


1. Builder

The Builder pattern is a creational design pattern that allows us to create complex objects from simple objects step by step. This design pattern helps us use the same code for creating different object views.

Imagine a complex object that requires incremental initialization of multiple fields and nested objects. Typically, the initialization code for such objects is hidden inside a mammoth constructor with dozens of parameters. Or even worse, it can be scattered all over the client code.

The Builder design pattern calls for separating the construction of an object from its own class. The construction of this object is instead assigned to special objects called builders and split into multiple steps. To create an object, you successively call builder methods. And you don’t need to go through all the steps – only those required for creating an object with a particular configuration.

You should apply the Builder design pattern :

  • when you want to avoid using a telescopic constructor (when a constructor has too many parameters, it gets difficult to read and manage);
  • when your code needs to create different views of a specific object;
  • when you need to compose complex objects.

Example:

Suppose you’re developing an iOS application for a restaurant and you need to implement ordering functionality. You can introduce two structures, Dish and Order, and with the help of the OrderBuilder object, you can compose orders with different sets of dishes.

// Design Patterns: Builder

import Foundation

// Models

enum DishCategory: Int {
    case firstCourses, mainCourses, garnishes, drinks
}

struct Dish {
    var name: String
    var price: Float
}

struct OrderItem {
    var dish: Dish
    var count: Int
}

struct Order {
    var firstCourses: [OrderItem] = []
    var mainCourses: [OrderItem] = []
    var garnishes: [OrderItem] = []
    var drinks: [OrderItem] = []
    
    var price: Float {
        let items = firstCourses + mainCourses + garnishes + drinks
        return items.reduce(Float(0), { $0 + $1.dish.price * Float($1.count) })
    }
}

// Builder

class OrderBuilder {
    private var order: Order?
    
    func reset() {
        order = Order()
    }
    
    func setFirstCourse(_ dish: Dish) {
        set(dish, at: order?.firstCourses, withCategory: .firstCourses)
    }
    
    func setMainCourse(_ dish: Dish) {
        set(dish, at: order?.mainCourses, withCategory: .mainCourses)
    }
    
    func setGarnish(_ dish: Dish) {
        set(dish, at: order?.garnishes, withCategory: .garnishes)
    }
    
    func setDrink(_ dish: Dish) {
        set(dish, at: order?.drinks, withCategory: .drinks)
    }
    
    func getResult() -> Order? {
        return order ?? nil
    }
    
    private func set(_ dish: Dish, at orderCategory: [OrderItem]?, withCategory dishCategory: DishCategory) {
        guard let orderCategory = orderCategory else {
            return
        }
        
        var item: OrderItem! = orderCategory.filter( { $0.dish.name == dish.name } ).first
        
        guard item == nil else {
            item.count += 1
            return
        }
        
        item = OrderItem(dish: dish, count: 1)
        
        switch dishCategory {
        case .firstCourses:
            order?.firstCourses.append(item)
        case .mainCourses:
            order?.mainCourses.append(item)
        case .garnishes:
            order?.garnishes.append(item)
        case .drinks:
            order?.drinks.append(item)
        }
    }
}

// Usage

let steak = Dish(name: "Steak", price: 2.30)
let chips = Dish(name: "Chips", price: 1.20)
let coffee = Dish(name: "Coffee", price: 0.80)

let builder = OrderBuilder()
builder.reset()
builder.setMainCourse(steak)
builder.setGarnish(chips)
builder.setDrink(coffee)

let order = builder.getResult()
order?.price

// Result:
// 4.30


2. Adapter

Adapter is a structural design pattern that allows objects with incompatible interfaces to work together. In other words, it transforms the interface of an object to adapt it to a different object.

An adapter wraps an object, therefore concealing it completely from another object. For example, you could wrap an object that handles meters with an adapter that converts data into feet.

You should use the Adapter design pattern:

  • when you want to use a third-party class but its interface doesn’t match the rest of your application’s code;
  • when you need to use several existing subclasses but they lack particular functionality and, on top of that, you can’t extend the superclass.

Example:

Suppose you want to implement a calendar and event management functionality in your iOS application. To do this, you should integrate the EventKit framework and adapt the Event model from the framework to the model in your application. An Adapter can wrap the model of the framework and make it compatible with the model in your application.

// Design Patterns: Adapter

import EventKit

// Models

protocol Event: class {
    var title: String { get }
    var startDate: String { get }
    var endDate: String { get }
}

extension Event {
    var description: String {
        return "Name: \(title)\nEvent start: \(startDate)\nEvent end: \(endDate)"
    }
}

class LocalEvent: Event {
    var title: String
    var startDate: String
    var endDate: String
    
    init(title: String, startDate: String, endDate: String) {
        self.title = title
        self.startDate = startDate
        self.endDate = endDate
    }
}

// Adapter

class EKEventAdapter: Event {
    private var event: EKEvent
    
    private lazy var dateFormatter: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MM-dd-yyyy HH:mm"
        return dateFormatter
    }()
    
    var title: String {
        return event.title
    }
    var startDate: String {
        return dateFormatter.string(from: event.startDate)
    }
    var endDate: String {
        return dateFormatter.string(from: event.endDate)
    }
    
    init(event: EKEvent) {
        self.event = event
    }
}

// Usage

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy HH:mm"

let eventStore = EKEventStore()
let event = EKEvent(eventStore: eventStore)
event.title = "Design Pattern Meetup"
event.startDate = dateFormatter.date(from: "06/29/2018 18:00")
event.endDate = dateFormatter.date(from: "06/29/2018 19:30")

let adapter = EKEventAdapter(event: event)
adapter.description

// Result:
// Name: Design Pattern Meetup
// Event start: 06-29-2018 18:00
// Event end: 06-29-2018 19:30


3. Decorator

The Decorator pattern is a structural design pattern that allows you to dynamically attach new functionalities to an object by wrapping them in useful wrappers.

No wonder this design pattern is also called the Wrapper design pattern. This name describes more precisely the core idea behind this pattern: you place a target object inside another wrapper object that triggers the basic behavior of the target object and adds its own behavior to the result.

Both objects share the same interface, so it doesn’t matter for a user which of the objects they interact with − clean or wrapped. You can use several wrappers simultaneously and get the combined behavior of all these wrappers.

You should use the Decorator design pattern :

  • when you want to add responsibilities to objects dynamically and conceal those objects from the code that uses them;
  • when it’s impossible to extend responsibilities of an object through inheritance.

Example :

Imagine you need to implement data management in your iOS application. You could create two decorators: EncryptionDecorator for encrypting and decrypting data and EncodingDecorator for encoding and decoding.

// Design Patterns: Decorator

import Foundation

// Helpers (may be not include in blog post)

func encryptString(_ string: String, with encryptionKey: String) -> String {
    let stringBytes = [UInt8](string.utf8)
    let keyBytes = [UInt8](encryptionKey.utf8)
    var encryptedBytes: [UInt8] = []
    
    for stringByte in stringBytes.enumerated() {
        encryptedBytes.append(stringByte.element ^ keyBytes[stringByte.offset % encryptionKey.count])
    }
    
    return String(bytes: encryptedBytes, encoding: .utf8)!
}

func decryptString(_ string: String, with encryptionKey: String) -> String {
    let stringBytes = [UInt8](string.utf8)
    let keyBytes = [UInt8](encryptionKey.utf8)
    var decryptedBytes: [UInt8] = []
    
    for stringByte in stringBytes.enumerated() {
        decryptedBytes.append(stringByte.element ^ keyBytes[stringByte.offset % encryptionKey.count])
    }
    
    return String(bytes: decryptedBytes, encoding: .utf8)!
}

// Services

protocol DataSource: class {
    func writeData(_ data: Any)
    func readData() -> Any
}

class UserDefaultsDataSource: DataSource {
    private let userDefaultsKey: String
    
    init(userDefaultsKey: String) {
        self.userDefaultsKey = userDefaultsKey
    }
    
    func writeData(_ data: Any) {
        UserDefaults.standard.set(data, forKey: userDefaultsKey)
    }
    
    func readData() -> Any {
        return UserDefaults.standard.value(forKey: userDefaultsKey)!
    }
}

// Decorators

class DataSourceDecorator: DataSource {
    let wrappee: DataSource
    
    init(wrappee: DataSource) {
        self.wrappee = wrappee
    }
    
    func writeData(_ data: Any) {
        wrappee.writeData(data)
    }
    
    func readData() -> Any {
        return wrappee.readData()
    }
}

class EncodingDecorator: DataSourceDecorator {
    private let encoding: String.Encoding
    
    init(wrappee: DataSource, encoding: String.Encoding) {
        self.encoding = encoding
        super.init(wrappee: wrappee)
    }
    
    override func writeData(_ data: Any) {
        let stringData = (data as! String).data(using: encoding)!
        wrappee.writeData(stringData)
    }
    
    override func readData() -> Any {
        let data = wrappee.readData() as! Data
        return String(data: data, encoding: encoding)!
    }
}

class EncryptionDecorator: DataSourceDecorator {
    private let encryptionKey: String
    
    init(wrappee: DataSource, encryptionKey: String) {
        self.encryptionKey = encryptionKey
        super.init(wrappee: wrappee)
    }
    
    override func writeData(_ data: Any) {
        let encryptedString = encryptString(data as! String, with: encryptionKey)
        wrappee.writeData(encryptedString)
    }
    
    override func readData() -> Any {
        let encryptedString = wrappee.readData() as! String
        return decryptString(encryptedString, with: encryptionKey)
    }
}

// Usage

var source: DataSource = UserDefaultsDataSource(userDefaultsKey: "decorator")
source = EncodingDecorator(wrappee: source, encoding: .utf8)
source = EncryptionDecorator(wrappee: source, encryptionKey: "secret")
source.writeData("Design Patterns")
source.readData() as! String

// Result:
// Design Patterns


4. Facade

Facade is a structural design pattern that provides a simplified interface to a library, a framework, or any other complex set of classes.

Imagine that your code has to deal with multiple objects of a complex library or framework. You need to initialize all these objects, keep track of the right order of dependencies, and so on. As a result, the business logic of your classes gets intertwined with implementation details of other classes. Such code is difficult to read and maintain.

The Facade pattern provides a simple interface for working with complex subsystems containing lots of classes. The Facade pattern offers a simplified interface with limited functionality that you can extend by using a complex subsystem directly. This simplified interface provides only the features a client needs while concealing all others.

You should use the Facade design pattern:

  • when you want to provide a simple or unified interface to a complex subsystem;
  • when you need to decompose a subsystem into separate layers.

Example:

Lots of modern mobile applications support audio recording and playback, so let’s suppose you need to implement this functionality. You could use the Facade pattern to hide the implementation of services responsible for the file system (FileService), audio sessions (AudioSessionService), audio recording (RecorderService), and audio playback (PlayerService). The Facade provides a simplified interface for this rather complex system of classes.

// Design Patterns: Facade

import AVFoundation

// Services (may be not include in blog post)

struct FileService {
    private var documentDirectory: URL {
        return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    }
    
    var contentsOfDocumentDirectory: [URL] {
        return try! FileManager.default.contentsOfDirectory(at: documentDirectory, includingPropertiesForKeys: nil)
    }
    
    func path(withPathComponent component: String) -> URL {
        return documentDirectory.appendingPathComponent(component)
    }
    
    func removeItem(at index: Int) {
        let url = contentsOfDocumentDirectory[index]
        try! FileManager.default.removeItem(at: url)
    }
}

protocol AudioSessionServiceDelegate: class {
    func audioSessionService(_ audioSessionService: AudioSessionService, recordPermissionDidAllow allowed: Bool)
}

class AudioSessionService {
    weak var delegate: AudioSessionServiceDelegate?
    
    func setupSession() {
        try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, with: [.defaultToSpeaker])
        try! AVAudioSession.sharedInstance().setActive(true)
        
        AVAudioSession.sharedInstance().requestRecordPermission { [weak self] allowed in
            DispatchQueue.main.async {
                guard let strongSelf = self, let delegate = strongSelf.delegate else {
                    return
                }
                
                delegate.audioSessionService(strongSelf, recordPermissionDidAllow: allowed)
            }
        }
    }
    
    func deactivateSession() {
        try! AVAudioSession.sharedInstance().setActive(false)
    }
}

struct RecorderService {
    private var isRecording = false
    private var recorder: AVAudioRecorder!
    private var url: URL
    
    init(url: URL) {
        self.url = url
    }
    
    mutating func startRecord() {
        guard !isRecording else {
            return
        }
        
        isRecording = !isRecording
        recorder = try! AVAudioRecorder(url: url, settings: [AVFormatIDKey: kAudioFormatMPEG4AAC])
        recorder.record()
    }
    
    mutating func stopRecord() {
        guard isRecording else {
            return
        }
        
        isRecording = !isRecording
        recorder.stop()
    }
}

protocol PlayerServiceDelegate: class {
    func playerService(_ playerService: PlayerService, playingDidFinish success: Bool)
}

class PlayerService: NSObject, AVAudioPlayerDelegate {
    private var player: AVAudioPlayer!
    private var url: URL
    weak var delegate: PlayerServiceDelegate?
    
    init(url: URL) {
        self.url = url
    }
    
    func startPlay() {
        player = try! AVAudioPlayer(contentsOf: url)
        player.delegate = self
        player.play()
    }
    
    func stopPlay() {
        player.stop()
    }
    
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
        delegate?.playerService(self, playingDidFinish: flag)
    }
}

// Facade

protocol AudioFacadeDelegate: class {
    func audioFacadePlayingDidFinish(_ audioFacade: AudioFacade)
}

class AudioFacade: PlayerServiceDelegate {
    private let audioSessionService = AudioSessionService()
    private let fileService = FileService()
    private let fileFormat = ".m4a"
    private var playerService: PlayerService!
    private var recorderService: RecorderService!
    weak var delegate: AudioFacadeDelegate?
    
    private lazy var dateFormatter: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd_HH:mm:ss"
        return dateFormatter
    }()
    
    init() {
        audioSessionService.setupSession()
    }
    
    deinit {
        audioSessionService.deactivateSession()
    }
    
    func startRecord() {
        let fileName = dateFormatter.string(from: Date()).appending(fileFormat)
        let url = fileService.path(withPathComponent: fileName)
        recorderService = RecorderService(url: url)
        recorderService.startRecord()
    }
    
    func stopRecord() {
        recorderService.stopRecord()
    }
    
    func numberOfRecords() -> Int {
        return fileService.contentsOfDocumentDirectory.count
    }
    
    func nameOfRecord(at index: Int) -> String {
        let url = fileService.contentsOfDocumentDirectory[index]
        return url.lastPathComponent
    }
    
    func removeRecord(at index: Int) {
        fileService.removeItem(at: index)
    }
    
    func playRecord(at index: Int) {
        let url = fileService.contentsOfDocumentDirectory[index]
        playerService = PlayerService(url: url)
        playerService.delegate = self
        playerService.startPlay()
    }
    
    func stopPlayRecord() {
        playerService.stopPlay()
    }
    
    func playerService(_ playerService: PlayerService, playingDidFinish success: Bool) {
        if success {
            delegate?.audioFacadePlayingDidFinish(self)
        }
    }
}

// Usage

let audioFacade = AudioFacade()
audioFacade.numberOfRecords()

// Result:
// 0


5. Template Method

The Template Method pattern is a behavioral design pattern that defines a skeleton for an algorithm and delegates responsibility for some steps to subclasses. This pattern allows subclasses to redefine certain steps of an algorithm without changing its overall structure.

This design pattern splits an algorithm into a sequence of steps, describes these steps in separate methods, and calls them consecutively with the help of a single template method.

You should use the Template Method design pattern:

  • when subclasses need to extend a basic algorithm without modifying its structure;
  • when you have several classes responsible for quite similar actions (meaning that whenever you modify one class, you need to change the other classes).

Example:

Suppose you’re working on an iOS app that must be able to take and save pictures. Therefore, your application needs to get permissions to use the iPhone (or iPad) camera and image gallery. To do this, you can use the PermissionService base class that has a specific algorithm.

To get permission to use the camera and gallery, you can create two subclasses, CameraPermissionService and PhotoPermissionService, that redefine certain steps of the algorithm while keeping other steps the same.

// Design Patterns: Template Method

import AVFoundation
import Photos

// Services

typealias AuthorizationCompletion = (status: Bool, message: String)

class PermissionService: NSObject {
    private var message: String = ""
    
    func authorize(_ completion: @escaping (AuthorizationCompletion) -> Void) {
        let status = checkStatus()
        
        guard !status else {
            complete(with: status, completion)
            return
        }
        
        requestAuthorization { [weak self] status in
            self?.complete(with: status, completion)
        }
    }

    func checkStatus() -> Bool {
        return false
    }
    
    func requestAuthorization(_ completion: @escaping (Bool) -> Void) {
        completion(false)
    }
    
    func formMessage(with status: Bool) {
        let messagePrefix = status ? "You have access to " : "You haven't access to "
        let nameOfCurrentPermissionService = String(describing: type(of: self))
        let nameOfBasePermissionService = String(describing: type(of: PermissionService.self))
        let messageSuffix = nameOfCurrentPermissionService.components(separatedBy: nameOfBasePermissionService).first!
        message = messagePrefix + messageSuffix
    }
    
    private func complete(with status: Bool, _ completion: @escaping (AuthorizationCompletion) -> Void) {
        formMessage(with: status)
        
        let result = (status: status, message: message)
        completion(result)
    }
}

class CameraPermissionService: PermissionService {
    override func checkStatus() -> Bool {
        let status = AVCaptureDevice.authorizationStatus(for: .video).rawValue
        return status == AVAuthorizationStatus.authorized.rawValue
    }
    
    override func requestAuthorization(_ completion: @escaping (Bool) -> Void) {
        AVCaptureDevice.requestAccess(for: .video) { status in
            completion(status)
        }
    }
}

class PhotoPermissionService: PermissionService {
    override func checkStatus() -> Bool {
        let status = PHPhotoLibrary.authorizationStatus().rawValue
        return status == PHAuthorizationStatus.authorized.rawValue
    }
    
    override func requestAuthorization(_ completion: @escaping (Bool) -> Void) {
        PHPhotoLibrary.requestAuthorization { status in
            completion(status.rawValue == PHAuthorizationStatus.authorized.rawValue)
        }
    }
}

// Usage

let permissionServices = [CameraPermissionService(), PhotoPermissionService()]

for permissionService in permissionServices {
    permissionService.authorize { (_, message) in
        print(message)
    }
}

// Result:
// You have access to Camera
// You have access to Photo

That’s all about in this article.


Conclusion

In this article, We understood about the five design patterns most frequently used in Swift. The ability to pick a design pattern in Swift that’s relevant for building a particular project allows you to build fully functional and secure applications that are easy to maintain and upgrade. You should certainly have design patterns in your skillset, as they not only simplify software development but also optimize the whole process and ensure high code quality.

Thanks for reading ! I hope you enjoyed and learned about the most frequently used Design Patterns in Swift. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

iOS – Is SOLID Valuable Design Principles Applicable For Swift ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, We will learn about most popular design principles SOLID in Swift. We will see that how SOLID is applicable for Swift. Now a days , a Maintainable and Reusable component is just a dream. Maybe not. SOLID principles, may be the way.

A famous quote about learning is :

Change is the end result of all true learning.

So Let’s begin.

Origin of the acronym SOLID

SOLID is an acronym named by Robert C. Martin (Uncle Bob). It represents 5 principles of object-oriented programming :

  • Single responsibility Principle
  • Open/Closed Principle
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle

If we apply these five principles:

  • We will have flexible code, which we can easily change and that will be both reusable and maintainable.
  • The software developed will be robust, stable and scalable (we can easily add new features).
  • Together with the use of the Design Patterns, it will allow us to create software that is highly cohesive (that is, the elements of the system are closely related) and loosely coupled (the degree of dependence between elements is low).

So, SOLID can solve the main problems of a bad architecture:

  • Fragility: A change may break unexpected parts—it is very difficult to detect if you don’t have a good test coverage.
  • Immobility: A component is difficult to reuse in another project—or in multiple places of the same project—because it has too many coupled dependencies.
  • Rigidity: A change requires a lot of efforts because affects several parts of the project.

Of course, as Uncle Bob pointed out in a his article, these are not strict rules, but just guidelines to improve the quality of your architecture.

Principles will not turn a bad programmer into a good programmer. Principles have to be applied with judgement. If they are applied by rote it is just as bad as if they are not applied at all.

Principles

The Single Responsibility Principle (SRP)

According to this principle, a class should have a reason, and only one, to change. That is, a class should only have one responsibility.

Now let’s describe Single Responsibility Principle says :

THERE SHOULD NEVER BE MORE THAN ONE REASON FOR A CLASS TO CHANGE.

Every time you create/change a class, you should ask yourself: How many responsibilities does this class have?

Let’s take a look into Swifty communication program.

import Foundation

class InterPlanetMessageReceiver {

    func receiveMessage() {
        print("Received the Message!")
    }

    func displayMessageOnGUI() {
      print("Displaying Message on Screen!")
    }
}

Now let’s understand what is Single Responsibility Principle (SRP) and how the above program doesn’t obey it.

SRP says, “Just because you can implement all the features in a single device, you shouldn’t”.

In Object Oriented terms it means: There should never be more than one reason for a class to change. It doesn’t mean you can’t have multiple methods but the only condition is that they should have one single purpose.

Why? Because it adds a lot of manageability problems for you in the long run.

Here, the InterPlanetMessageReceiver class does the following:

  • It receives the message.
  • It renders it on UI.

And, two applications are using this InterPlanetMessageReceiver class:

  • A messaging application uses this class to receive the message
  • A graphical application uses this class to draw the message on the UI

Do you think it is violating the SRP?

YES, The InterPlanetMessageReceiver class is actually performing two different things. First, it handles the messaging, and second, displaying the message on GUI. This causes some interesting problems:

  • Swifty must include the GUI into the messaging application and also while deploying the messaging application, we must include the GUI library.
  • A change to the InterPlanetMessageReceiver class for the graphical application may lead to a change, build, and test for the messaging application, and vice-versa.

Swifty got frustrated with the amount of changes it required. He thought it would be a minute job but now he has already spent hours on it. So he decided do make a change into his program and fix this dependency.

This is what Swifty came up with

import Foundation

// Handles received message
class InterPlanetMessageReceiver {

    func receive() {
        print("Received the Message!")
    }
}

// Handles the display part
class InterPlanetMessageDisplay {

    func displayMessageOnGUI() {
      print("Displaying Message on Screen!")
    }
}

Here’s how Swifty explained this:

InterPlanetMessageReceiver class will be used by the messaging application, and the InterPlanetMessageDisplay class will be used by the graphical application. We could even separate the classes into two separate files, and that will allow us not to touch the other in case a change is needed to be implemented in one.

Finally, Swifty noted down :Why we need SRP?

  • Each responsibility is an agent of change.
  • Code becomes coupled if classes have more than one responsibility.

Open/Closed Principle

According to this principle, we must be able to extend the a class without changing its behaviour. This is achieved by abstraction.

Now let’s describe Open/Closed Principle says :

SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.) SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION.

If you want to create a class easy to maintain, it must have two important characteristics:

  • Open for extension: You should be able to extend or change the behaviours of a class without efforts.
  • Closed for modification: You must extend a class without changing the implementation.

Let’s see our swifty example. Swifty was quite happy with these change and later he celebrated it with a drink in Swiftzen’s best pub and there his eyes fell upon an artifact hanging on the front wall and he found all the symbols he received in the message. Quickly, he opened his diary and completed deciphering all those shapes.

Next day when he returned back, he thought why not fix the DrawGraphic class which draws only circle shape, to include the rest of the shapes and display the message correctly.

// This is the DrawGraphic
class DrawGraphic {

  func drawShape() {
     print("Circle is drawn!")
  }
}

// Updated Class code

enum Shape {
  case circle
  case rectangle
  case square
  case triangle
  case pentagon
  case semicircle
}
class circle {

}

// This is the DrawGraphic
class DrawGraphic {

  func drawShape(shape: Shape) {
     switch shape {
        case .circle:
          print("Circle is drawn")
        case .rectangle:
          print("Rectangle is drawn")
        case square:
          print("Square is drawn")
        case triangle:
          print("Triangle is drawn")
        case pentagon:
          print("Pentagon is drawn")
        case semicircle:
          print("Semicircle is drawn")
        default:
          print("Shape not provided")
     }
  }
}

Swifty was not happy with these changes, what if in future a new shape shows up, after all he saw in the artifacts that there were around 123 shapes. This class will become one fat class. Also, DrawGraphics class is used by other applications and so they also have to adapt to this change. it was nightmare for Swifty.

Open Closed Principle solves nightmare for Swifty. At the most basic level, this means, you should be able to extend a class behavior without modifying it. It’s just like I should be able to put on a dress without doing any change to my body. Imagine what would happen if for every dress I have to change my body.

After hours of thinking, Swifty came up with below implementation of DrawGraphic class.

protocol Draw {
    func draw()
}

class Circle: Draw {
    func draw() {
        print("Circle is drawn!")
    }
}

class Rectangle: Draw {
    func draw() {
        print("Rectangle is drawn!")
    }
}

class DrawGraphic {
    func drawShape(shape: Draw) {
        shape.draw()
    }
}

let circle = Circle()
let rectangle = Rectangle()
let drawGraphic = DrawGraphic()

drawGraphic.drawShape(shape: circle)  // Circle is drawn!
drawGraphic.drawShape(shape: rectangle) // Rectangle is drawn!

Since the DrawGraphic is responsible for drawing all the shapes, and because the shape design is unique to each individual shape, it seems only logical to move the drawing for each shape into its respective class.

That means the DrawGraphic still have to know about all the shapes, right? Because how does it know that the object it’s iterating over has a draw method? Sure, this could be solved with having each of the shape classes inherit from a protocol: the Draw protocol (this can be an abstract class too).

Circle and Rectangle classes holds a reference to the protocol, and the concrete DrawGraphic class implements the protocol Draw class. So, if for any reason the DrawGraphic implementation is changed, the Circle and Rectangle classes are not likely to require any change or vice-versa.

Liskov Subsitution Principle

This principle, introduced by Barbara Liskov in 1987, states that in a program any class should be able to be replaced by one of its subclasses without affecting its functioning.

Now let’s describe Liskov Substitution Principle says :

FUNCTIONS THAT USE POINTERS OR REFERENCES TO BASE CLASSES MUST BE ABLE TO USE OBJECTS OF DERIVED CLASSES WITHOUT KNOWING IT.

Inheritance may be dangerous and you should use composition over inheritance to avoid a messy codebase. Even more if you use inheritance in an improper way.

This principle can help you to use inheritance without messing it up.

Let’s see our swifty example. Swifty was implementing the SenderOrigin class to know whether the sender is from a Planet or not.

The Sender class looked something like this

Class Planet {
  func orbitAroundSun() {
  }
}

class Earth: Planet {
  func description() {
    print("It is Earth!")
  }
}

class Pluto: Planet {
  func description() {
    print("It is Pluto!")
  }
}

class Sender {
  func senderOrigin(planet: Planet) {
    planet.description()
  }
}

In the class design, Pluto should not inherit the Planet class because it is a dwarf planet, and there should be a separate class for Planet that has not cleared the neighborhood around its orbit and Pluto should inherit that.

So the principle says that Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.

Swifty whispered it is the polymorphism. Yes it is. “Inheritance” is usually described as an “is a” relationship. If a “Planet” is a “Dwarf”, then the “Planet” class should inherit the “Dwarf” class. Such “Is a” relationships are very important in class designs, but it’s easy to get carried away and end up with a wrong design and a bad inheritance.

The “Liskov’s Substitution Principle” is just a way of ensuring that inheritance is used correctly.

In the above case, both Earth and Pluto can orbit around the Sun but Pluto is not a planet. It has not cleared the neighborhood around its orbit. Swifty understood this and changed the program.

class Planet {
    func oribitAroundSun() {
        print("This planet Orbit around Sun!")
    }
}

class Earth: Planet {
    func description() {
        print("Earth")
    }
}

class DwarfPlanet: Planet {
    func notClearedNeighbourhoodOrbit() {

    }
}

class Pluto: DwarfPlanet {
  func description() {
        print("Pluto")
    }
}

class Sender {
    func senderOrigin(from: Planet) {
        from.description()
    }
}

let pluto = Pluto()
let earth = Earth()

let sender = Sender()
sender.senderOrigin(from: pluto) // Pluto
sender.senderOrigin(from: earth) // Earth

Here, Pluto inherited the planet but added the notClearedNeigbourhood method which distinguishes a dwarf and regular planet.

  • If LSP is not maintained, class hierarchies would be a mess, and if a subclass instance was passed as parameter to methods, strange behavior might occur.
  • If LSP is not maintained, unit tests for the base classes would never succeed for the subclass.

Swifty can design objects and apply LSP as a verification tool to test the hierarchy whether inheritance is properly done.

Interface Segregation Principle

The Principle of segregation of the interface indicates that it is better to have different interfaces (protocols) that are specific to each client, than to have a general interface. In addition, it indicates that a client would not have to implement methods that he does not use.

Now let’s describe Interface Segragation Principle says :

CLIENTS SHOULD NOT BE FORCED TO DEPEND UPON INTERFACES THAT THEY DO NOT USE.

This principle introduces one of the problems of object-oriented programming: the fat interface.

An interface is called “fat” when has too many members/methods, which are not cohesive and contains more information than we really want. This problem can affect both classes and protocols.

Let’s continue our swifty example. Swifty was quite astonished with the improvement in his program. All the changes were making more sense. Now, it was time to share this code with different planet. Swiftzen 50% GDP was dependent on selling softwares and many planet has requested and signed MOU for the Inter Planet communication system.

Swifty was ready to sell the program and but he was not satisfied with current client interface. Let’s us look into it.

protocol interPlanetCommunication {
  func switchOnAntenna()
  func setAntennaAngle()
  func transmitMessage()
  func receivedMessage()
  func displayMessageOnGUI()
}

Now for anyone who want to use interPlanetCommunication, he has to implement all the five methods even-though they might not required.

So the principle says that Many client-specific interfaces are better than one general purpose interface. The principle ensures that Interfaces are developed so that each of them have their own responsibility and thus they are specific, easily understandable, and re-usable.

Swifty quickly made changes to his program interface:

protocol antenna {
  func switchOnAntenna()
  func setAntennaAngle()
}

protocol message {
  func transmitMessage()
  func receivedMessage()
}

protocol dispaly {
  func displayMessageOnGUI()
}

Dependency Inversion Principle

According to the Dependency inversion principle:

“HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS.”

“ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS.”

This principle tries to reduce the dependencies between modules, and thus achieve a lower coupling between classes.

This principle is the right one to follow if you believe in reusable components.

DIP is very similar to Open-Closed Principle: the approach to use, to have a clean architecture, is decoupling the dependencies. You can achieve it thanks to abstract layers.

Let’s continue our swifty example. Before finally shipping the program to all the clients, Swifty was trying to fix the password reminder class which looks like this.

class PasswordReminder {
  func connectToDatabase(db: SwiftZenDB) {
    print("Database Connected to SwiftzenDB")
  }

  func sendReminder() {
    print("Send Reminder")
  }
}

PasswordReminder class is dependent on a lower level module i.e. database connection. Now, let suppose that you want to change the database connection from Swiftzen to Objective-Czen, you will have to edit the PasswordReminder class.

Finally the last principle states that Entities must depend on abstractions not on concretions.

To fix above program Swifty made these changes:

protocol DBConnection {
  func connection()
}

class SwiftzenDB: DBConnection {
  func connection() {
    print("Connected to SwiftzenDB")
  }
}

class PasswordReminder {
  func connectToDatabase(db: DBConnection) {
    db.connection()
  }

  func sendReminder() {
    print("Send Reminder")
  }
}

The DBConnection protocol has a connection method and the SwiftzenDB class implements this protocol, also instead of directly type-hinting SwiftzenDB class in PasswordReminder, Swifty instead type-hint the protocol and no matter the type of database your application uses, the PasswordReminder class can easily connect to the database without any problems and OCP is not violated.

The point is rather than directly depending on the SwiftzenDB, the passwordReminder depends on the abstraction of some specification of Database so that if any the Database conforms to the abstraction, it can be connection with the PasswordReminder and it will work.

That’s all about in this article.

Conclusion

In this article, We understood about SOLID principles in Swift. We learnt that how SOLID is application for Swift. If we follow SOLID principles judiciously, we can increase the quality of our code. Moreover, our components can become more maintainable and reusable.

The mastering of these principles is not the last step to become a perfect developer, actually, it’s just the beginning. We will have to deal with different problems in our projects, understand the best approach and, finally, check if we are breaking some principles.

We have 3 enemies to defeat: Fragility, Immobility and Rigidity. SOLID principles are our weapons. We tried to explain the SOLID concepts in Swift easy way with examples.

Thanks for reading ! I hope you enjoyed and learned about SOLID Principles in Swift. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – An Overview of Room Persistent Library

Hello Readers, CoolMonkTechie heartily welcomes you in this article (An Overview of Room Persistent Library).

In this article, we will learn about Android Room Persistent Library Overview. We will try to understand the basics of Room, how to use it, major components in Room and type converters in Room.

For better understanding about Android Room Persistent Library, we will discuss the below points:

  • What is Room in Android ?
  • What are the advantages of Room in Android Application ?
  • How to use it in our Project or Application?
  • What is major components of Room in Android ?
  • Type Converters in Room

A famous quote about learning is :

He who learns but does not think, is lost! He who thinks but does not learn is in great danger.

So, Let’s start.

What is Room in Android ?

Room is an Android persistence library, which is part of Google’s Android Jetpack project.

According to the Android Documentation, “Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.

The library helps us create a cache of our app’s data on a device that’s running our app. This cache, which serves as our app’s single source of truth, allows users to view a consistent copy of key information within our app, regardless of whether users have an internet connection.

It means that Apps that handle significant amounts of structured data can benefit from persisting that data locally. The most common use case is to cache relevant pieces of data. That way, when the device cannot access the network, the user can still browse that content while they are offline. Any user-initiated content changes are then synced to the server after the device is back online.

What is the advantages of Room in Android Application ?

There are multiple advantages of using Room as compared to other alternate solutions like SQLiteOpenHelper:

  • Compile-time verification of queries.
  • Reduces boilerplate code.
  • Easy to understand and use.
  • Easy integration with RxJava, LiveData and Kotlin Coroutines.

How to use it in our Project or Application?

To use Room in your app, add the following dependencies to our app’s build.gradle file:

dependencies {
  def room_version = "2.2.5"

  implementation "androidx.room:room-runtime:$room_version"
  annotationProcessor "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor

  // optional - Kotlin Extensions and Coroutines support for Room
  implementation "androidx.room:room-ktx:$room_version"

  // optional - RxJava support for Room
  implementation "androidx.room:room-rxjava2:$room_version"

  // optional - Guava support for Room, including Optional and ListenableFuture
  implementation "androidx.room:room-guava:$room_version"

  // Test helpers
  testImplementation "androidx.room:room-testing:$room_version"
}

Note: For Kotlin-based apps, make sure we use kapt instead of annotationProcessor. We should also add the kotlin-kapt plugin.

What is major components of Room in Android ?

There are 3 major components in Room:

  • Database: Contains the database holder and serves as the main access point for the underlying connection to our app’s persisted, relational data.
  • Entity: Represents a table within the database.
  • DAO: Contains the methods used for accessing the database.

Our application uses the Room database to get the data access objects, or DAOs, associated with our database. The app then uses each DAO to get entities from the database and save any changes to those entities back to the database. Finally, the app uses an entity to get and set values that correspond to table columns within the database.

This relationship among the different components of Room appears in Figure 1:

1. Database

As mentioned earlier, it contains the database holder and serves as the main access point for the underlying connection to our app’s persisted, relational data. The class that’s annotated with @Database should satisfy the following conditions:

  • Be an abstract class that extends RoomDatabase.
  • Include the list of entities associated with the database within the annotation.
  • Contain an abstract method that has 0 arguments and returns the class that is annotated with @Dao.

At runtime, you can acquire an instance of Database by calling Room.databaseBuilder() or Room.inMemoryDatabaseBuilder().

@Database(entities = arrayOf(User::class), version = 1)
abstract class UserDatabase : RoomDatabase() {
  abstract fun userDao(): UserDao
}

To get an instance of the database, you can use the following method:

val db = Room.databaseBuilder(
    applicationContext,
    UserDatabase::class.java, "users-db"
    ).build()

We have noted that :

  • If our app runs in a single process, we should follow the singleton design pattern when instantiating an AppDatabase object. Each RoomDatabase instance is fairly expensive, and we rarely need access to multiple instances within a single process.
  • If our app runs in multiple processes, include enableMultiInstanceInvalidation() in our database builder invocation. That way, when we have an instance of AppDatabase in each process, we can invalidate the shared database file in one process, and this invalidation automatically propagates to the instances of AppDatabase within other processes.”

2. Entity

An Entity represents a table within a database. This class is annotated with @Entity annotation. Data members in these class represent the columns within a table. For example :

@Entity
data class User(
  @PrimaryKey val uid: Int,
  @ColumnInfo(name = "first_name") val firstName: String?,
  @ColumnInfo(name = "last_name") val lastName: String?
)
  • All the fields in an entity must either be public or have getter & setter methods.
  • Entity class should have an empty constructor (if all fields are accessible) or a parametrised constructor which takes all the fields. Room can also use partial constructors.
  • Each entity class must have at least one primary key. We can use either @PrimaryKey annotation to define single field primary key or primaryKeys attribute of @Entity annotation for multiple fields. We can also use autoGenerate property of @PrimaryKey annotation to automatically assign primary keys.
@Entity(primaryKeys = arrayOf("firstName", "lastName"))
  • By default, Room uses the class name as the database table name. If we want the table to have a unique name, set the tableName property of the @Entity annotation. Similarly, we can use the name property of the @ColumnInfo annotation for defining the name of columns.
@Entity(tableName = "users")
  • If we don’t want to persist in any field, we can annotate them using @Ignore.
@Ignore val picture: Bitmap?
  • We can use the indices property of @Entity annotation to add indices to an entity. Also, we can create unique indices by setting the unique property of an @Index annotation to true.
@Entity(indices = arrayOf(Index(value = ["last_name", "address"])))@Entity(indices = arrayOf(Index(value = ["first_name", "last_name"],
        unique = true)))

3. Data Access Object (DAO)

DAOs provide an API for accessing the database. This is an interface which is annotated with @Dao annotation. All the methods in this interface are used for getting data from the database or changing the database. These methods are annotated with annotations like @Query, @Insert, @Delete.

@Dao
interface UserDao {
  @Query("SELECT * FROM user")
  fun getAll(): List<User>
  
  @Query("SELECT * FROM user WHERE uid IN (:userIds)")
  fun loadAllByIds(userIds: IntArray): List<User>
  
  @Insert
  fun insertAll(vararg users: User)
  
  @Delete
  fun delete(user: User)
}

Here, all queries using UserDao are made on the caller thread. So we should take care that no method is invoked from the UI(main) thread.

Type Converters in Room

Sometimes, we might need to persist a custom data type in a single database column. We can use type converters for these types of use cases.

class Converters {
  @TypeConverter
  fun fromTimestamp(value: Long?): Date? {
  return value?.let { Date(it) }
  }

  @TypeConverter
  fun dateToTimestamp(date: Date?): Long? {
  return date?.time?.toLong()
  }
}

Next, we have to add the @TypeConverters annotation to the RoomDatabase class so that Room can use the converter, we’ve defined for each entity and DAO in that RoomDatabase.

@Database(entities = arrayOf(User::class), version = 1)
@TypeConverters(Converters::class)
abstract class UserDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

So Room takes care of these concerns for us, we highly recommend using Room instead of SQLite.

That’s all about in this article.

Conclusion

In this article, we understood about Android Room Persistent Library Overview like Basic, advantages, How to use it, major components and custom type converters in Room.

Thanks for reading! I hope you enjoyed and learned about the basic of Android Room Persistent Library. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

You can find Other articles of CoolmonkTechie as below link :

You can also follow official website and tutorials of Android as below links :

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – How Does RecyclerView Work Internally?

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, we will learn about how recyclerView actually works in the Android system. This article will focus the below points to understand the Android RecyclerView Working Concepts:

  • Overview
  • What is RecyclerView?
  • The Building Components of RecyclerView
  • The Benefits of RecyclerView
  • RecyclerView Used Patterns
  • How it actually works?
  • The View Optimization of RecyclerView

A famous quote about learning is :

Tell me and I forget, teach me and I may remember, involve me and I learn.

So Let’s begin one by one.

Overview

Displaying a list or grid of data is one of the most common UI tasks in Android. Lists vary from simple to very complex. A list of text views might show simple data, such as a shopping list. A complex list, such as an annotated list of vacation destinations, might show the user many details inside a scrolling grid with headers.

To support all these use cases, Android provides the RecyclerView widget. So what’s next.

What is RecyclerView?

RecyclerView is a ViewGroup, which populates a list on a collection of data provided with the help of ViewHolder and draws it to the user on-screen.

The Building Components of RecyclerView

The major components of RecyclerView are:

  • Adapter
  • ViewHolder
  • LayoutManager

1. Adapter

It is a subtype of RecyclerView. Adapter class. This takes the data set which has to be displayed to the user in RecyclerView. It is like the main responsible class to bind the views and display it.

Most of the tasks happen inside the adapter class of the recyclerView.

2. ViewHolder

ViewHolder is a type of a helper class that helps us to draw the UI for individual items that we want to draw on the screen.

All the binding of Views of the individual items happens in this class. It is a subclass of RecyclerView.ViewHolder class.

3. LayoutManager

LayoutManager in recyclerView helps us to figure out how we need to display the items on the screen. It can be linearly or in a grid. RecyclerView provides by default a few implementations of layoutManager out of the box.

It is like the governing body of recyclerView which tells the recyclerView’s adapter when to create a new view.

The Benefits of RecyclerView

The greatest benefit of RecyclerView is that it is very efficient for large lists:

  • By default, RecyclerView only does work to process or draw items that are currently visible on the screen. For example, if our list has a thousand elements but only 10 elements are visible, RecyclerView does only enough work to draw 10 items on the screen. When the user scrolls, RecyclerView figures out what new items should be on the screen and does just enough work to display those items.
  • When an item scrolls off the screen, the item’s views are recycled. That means the item is filled with new content that scrolls onto the screen. This RecyclerView behavior saves a lot of processing time and helps lists scroll fluidly.
  • When an item changes, instead of redrawing the entire list, RecyclerView can update that one item. This is a huge efficiency gain when displaying lists of complex items!

In the sequence shown below, we can see that one view has been filled with data, ABC. After that view scrolls off the screen, RecyclerView reuses the view for new data, XYZ.

RecyclerView Used Patterns

RecyclerView uses Adapter pattern to display complex lists in the UI Screen after transform app data.

If we ever travel between countries that use different electric sockets, we probably know how we can plug your devices into outlets by using an adapter. The adapter lets you convert one type of plug to another, which is really converting one interface into another.

The adapter pattern in software engineering helps an object to work with another API. RecyclerView uses an adapter to transform app data into something the RecyclerView can display, without changing how the app stores and processes the data.

For the sleep-tracker app, we build an adapter that adapts data from the Room database into something that RecyclerView knows how to display, without changing the ViewModel.

How it actually works?

So, now we are going to discuss how the recyclerView actually works. When we talk about recyclerView, you would always hear someone saying that it recycles the views. But what does it actually mean?

So, let’s say when we are scrolling the list which has 50 items in the collection and we show only 5 items at once in the list.

Here, item 1 to item 5 is the ones that are visible on the screen. item x is the one that will be loaded next on the screen when we scroll up. All the items here have their own instance of ViewHolder and the ViewHolder here is helpful for caching the specific item’s view.

This is how recycling of views happens in recyclerView which is one of the main reasons for the better improvement of recyclerView. In this process, the views of the item are reused to draw new items on the screen.

Similarly, if we have multiple view types, let’s say ViewType1 and ViewType2 then we would have two different collections of scrapped view of type ViewType1 and ViewType2.

And while recycling the views, the ViewType1 view will be allocated to only views of ViewType1 and ViewType2 views will be allocated to ViewType2 views.

This is how recyclerView works internally and efficiently.

The View Optimization of RecyclerView

RecyclerView optimizes the view using ViewHolders.

So, let us say we have 100 items be displayed on the list, and we want to show 5 items on the screen.

Each item here has 1 TextView and 1 ImageView in the item.

So, to map each view using findViewById is always an expensive task and just imagine the number of findViewByIds we might need to map all the TextViews and ImageViews of 100 items i.e 200 findViewByIds.

So, when we are using RecyclerView, then only 6 items are created initially with 5 loaded at once to be displayed on-screen and one is the one to be loaded.

Now, if we scroll the list then we have 7 viewHolders. One each for scrapped view and to be loaded view and 5 for the ones which are displayed.

So, at a time, maximum findViewByIds that we are using are only 14 as we have a maximum of 7 ViewHolders.

Because of ViewHolders and recycling of views, we have got the performance improvement in RecyclerViews.

That’s all about in this article.

Conclusion

In this article, We understood how recyclerView actually works in the Android system. This article demonstrates RecyclerView Concepts, Building Blocks , Benefits, Used Patterns, Internal working process and the reasons behind view optimization and performance improvement in RecyclerView.

Thanks for reading ! I hope you enjoyed and learned about Android RecyclerView Concepts. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – How To Secure API Keys Using Android NDK ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, we will learn about how to secure API Keys using the Android Native Development Kit. We will focus the below points to understand the API Keys Security Concepts in Android NDK:

  • What is the current problem during secure API Keys?
  • What is the proposed solution to secure the API Keys?
  • How to do this in Android?

A famous quote about learning is :

The more that you read, the more things you will know. The more that you learn, the more places you’ll go.

So Let’s begin one by one.

Overview

What is the current problem during secure API Keys?

Here First question, What is the current problem during secure API Keys?

The Answer is :

While developing Android applications, we use various third-parties libraries that make the development of our application fast. In these libraries, we just call some functions according to our need and we don’t know the code of these functions and we don’t care about that. But to call these functions, we need API keys that are different for different users. Some of these libraries are paid and if somehow, someone gets our API key then we might land to high payment bills and many other problems. During the starting days to Android development, we put our API keys either in strings.xml file or in gradle file.

strings.xml file

Following is an example of storing an API key in strings.xml file:

<resources>
    <string name="app_name">SecureAPI</string>
    <string name="MyAPIKey">YOUR_API_KEY_HERE</string>
</resources>

The problem with approach is that anyone can get the API key by reverse engineering.

gradle file

Another approach that was used is the gradle file approach. Here we add the API key in the gradle.properties file:

#gradle.properties file

#API Key
APIKey = "YOUR_API_KEY_HERE"

After that, import the API key as buildConfigField in the build.gradle file.

buildTypes {
    debug {
        buildConfigField 'String', "ApiKey", MyAPIKey
        resValue 'string', "api_key", MyAPIKey
    }
    ...
}

But still anyone can get the API key by reverse engineering your code. So, both methods failed to secure the API keys. We need a certain concrete method that can be used so that even after reverse-engineering the code, no one can get the desired API key. 

Cool !! So We understood the problem of secure API keys in Android development.

What is the proposed solution to secure the API Keys ?

So the next question is, What is the proposed solution to secure the API Keys ? And what should we do so that even after reverse engineering no one can get the API key ?

The Answer is :

One solution to the above problem can be the use of native language in our application code. In the native languages like in C or C++, the Android Native Development Kit(NDK) compiles the code to .so file. The benefit with this .so file is that it contains binary numbers i.e. in the form of 0s and 1s. So, even after reverse engineering, we will get 0s and 1s and it is very difficult to identify what is written in the form of 0s and 1s.

Great !!

There are methods to get the code from 0s and 1s also, but as I said earlier, we are just providing some extra security layers to our code.

How to do this in Android ?

So next, we will discuss that How to do this in Android ?

The Answer is :

In Android, we have the support of Native languages with the help of the Android Native Development Kit (NDK). Also, there is JNI (Java Native Interface) in Android. JNI defines a way for the byte code that is generated from the Java or Kotlin code to interact with the native code i.e. code written in C or C++.

Three Approaches to secure our API keys

So, with the help of Android NDK, we can secure the API keys. Based on the versions of Android Studio, we have three approaches to secure our API keys using :

  • The Native C++ template
  • CMake
  • ndk-build

But before moving on to these approaches, there are some prerequisites. So, before moving onto that, we have to download some tools. Follow the below steps:

  1. In Android Studio, click on Tools > SDK Manager > SDK Tools.
  2. Select LLBDNDK, and CMake.
  3. Click on Apply and after downloading and installing click on OK.

  • LLBD: It is used by Android Studio to debug the native code present in the project.
  • NDK: Native Development Kit(NDK) is used to code in C and C++ i.e. native languages for Android.
  • CMake: It is an open-source system that manages the build process in an operating system and a compiler-independent manner.

Now, we have done with downloading the tools, let’s quickly move on to the approaches of securing the API keys.

1. The Native C++ template

In the latest versions of Android Studio, we have support for native code i.e. for the C and C++. 

We can find that by default we will be having native-lib.cpp file and the CMakeLists.txt file added to our project under the cpp directory. The native-lib.cpp file is the file that contains our API keys. We can add our API keys in the file as below:

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_coolmonktechie_myapplication_APIKeyLibrary_getAPIKey(JNIEnv* env, jobject /* this */) {
    std::string api_key = "YOUR_API_KEY_GOES_HERE";
    return env->NewStringUTF(api_key.c_str());
}

Following is the description of the above code:

  • Here, we have to follow the combination of PackageName_ActivityName_MethodName.
  • In the above example, com_coolmonktechie_myapplication is the package name, APIKeyLibrary is the file name and getAPIKey is the method that is used to get the API keys from the native code.
  • We can directly return the API key but normally people use some encryption technique to encrypt the API key. So, the NewStringUTF() method is used to do the UTF-8 encoding.

Now, to use our API key in the Activity or in any file, go to the Activity or the file where we want to use our API keys. To load the native code that we have written, we need to call the System.loadLibrary(“native-lib”) method in the init block.

init {
        System.loadLibrary("native-lib")
}

Now, declare a Kotlin external function with the same name as used in the native code.

external fun getAPIKey(): String

Finally, we can get the API key by calling:

APIKeyLibrary.getAPIKey()

That’s all! We have secured our API key.

2. CMake

Apart from using the Native C++ template, we can use the CMake to secure the API keys.

CMake is used to control the software compilation process using simple platform and compiler independent configuration files, and generate native makefiles and workspaces that can be used in the compiler environment of our choice.

After installing the required tools, Under the app/src/main directory, create a directory named cpp. In the cpp directory, create a native file where we want to store our API keys. So, create a file named api-keys.cpp and add the below code:

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_coolmonktechie_myapplication_APIKeyLibrary_getAPIKey(JNIEnv* env, jobject /* this */) {
    std::string api_key = "YOUR_API_KEY_GOES_HERE";
    return env->NewStringUTF(api_key.c_str());
}

In the app/ directory, we need to add one text file named CMakeLists.txt file. It is a CMake build script. Add the below content into it:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# We can define multiple libraries, and CMake builds them for us.
# Gradle automatically packages shared libraries with our APK.

add_library( # Sets the name of the library.
api-keys

# Sets the library as a shared library.
        SHARED

# Provides a relative path to our source file(s).
src/main/cpp/api-keys.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, we only need to specify the name of the public NDK library
# we want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
log-lib

# Specifies the name of the NDK library that
# we want CMake to locate.
        log )

# Specifies libraries CMake should link to our target library. We
# can link multiple libraries, such as libraries we define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
native-lib

# Links the target library to the log library
# included in the NDK.
        ${log-lib} )

Now, We have to specify the path of our CMakeLists file in the build.gradle file. So, add the below code in build.gradle file:

android {
    ...
    defaultConfig {
        ...
    }
    buildTypes {
        ...
    }
    externalNativeBuild {
        cmake {
            path 'CMakeLists.txt'
        }
    }
}

Now, to access the API keys from our Activity or file.

3. ndk-build

To compile the native code present in the project, Android Studio supports the ndk-build. Here, we will be having an Android.mk build file that is used by ndk-build.

The Android.mk file is present inside the jni/ directory. It describes our sources and shared libraries to the build system. The basic purpose of the Android.mk file is to define project-wide settings that are not defined by the build system or by Application.mk or by environment variables. Also, the syntax of the Android.mk file allows us to group our sources into modules.

To use ndk-build, Under the app/src/main directory, create a directory named jni. Here we will be having our .mk files and the native code file. In the jni directory that we have created in the previous step, add one file named Android.mk and add the below lines of code to it:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := api-keys
LOCAL_SRC_FILES := api-keys.c

include $(BUILD_SHARED_LIBRARY)

Following is the description of the above code:

  • The LOCAL_PATH variable indicates the location of the source file. my-dir is a macro function provided by the build system to return the current directory.
  • The CLEAR_VARS is used to clear many LOCAL_XXX variables for us like LOCAL_MODULE, LOCAL_SRC_FILES, etc. It doesn’t clear LOCAL_PATH.
  • The LOCAL_MODULE variable stores the name of the module that we want to build. The module name must be unique and we shouldn’t use any space in the module name.
  • The LOCAL_SRC_FILES variable contains a list of C or C++ files that are present in the module.
  • The BUILD_SHARED_LIBRARY variable is used to tie everything together. It determines what to build, and how to do it. It collects the information that we defined in LOCAL_XXX variables since the most recent include.

In the jni directory, create another file named Application.mk file and add the below code:

APP_ABI := all

The Application.mk file is used to specify the project-wide settings for the ndk-build.

The variable APP_ABI is used to specify the ABIs whose code should be generated by the build system. By default, the build system generates the code for all non-deprecated ABIs.

The last file to be added in the jni directory is our native code file. So, in the jni directory, add one file named api-keys.c and add the below code into it:

#include <jni.h>

//For first API key
JNIEXPORT jstring JNICALL
Java_com_coolmonktechie_myapplication_APIKeyLibrary_getAPIKey(JNIEnv *env, jobject instance) {

    return (*env)->  NewStringUTF(env, "YOUR_API_GOES_HERE");

}

After adding the required files in your jni directory, our next aim is to provide the path of our Android.mk file in the build.gradle file.

android {
    ...
    defaultConfig {
        ...
    }
    buildTypes {
        ...
    }
    externalNativeBuild {
        ndkBuild {
            path 'src/main/jni/Android.mk'
        }
    }
}

Now, to access the API keys from your Activity or file.

That’s all about in this article.

Conclusion

In this article, We understood how to secure our API keys with the help of the Android Native Development Kit. We saw three methods of doing so i.e. the ndk-build method, the CMake method and the easiest one i.e. using the native c++ template in our Application project..

Thanks for reading ! I hope you enjoyed and learned about Android Secure API Keys Concepts and Methods. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – An Overview of Android JetPack

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, we will learn about Android Jetpack and Jetpack related components. We will discuss about the below Android Jetpack related topics :

  • What is Android Jetpack and why should we use it ?
  • What is Android Jetpack Components ?

A famous quote about learning is :

” That is what learning is. You suddenly understand something you’ve understood all your life, but in a new way.”

So Let’s begin.

In the above diagram, It represents a set of components, tools and guidance to make great Android apps. 

Cool !!

So first, we understand the Android Jetpack.

What is Android Jetpack ?

“Jetpack is a suite of libraries, tools, and guidance to help developers write high-quality apps more easily. These components help you follow best practices, free you from writing boilerplate code, and simplify complex tasks, so you can focus on the code you care about.”

Jetpack comprises the androidx.* package libraries, unbundled from the platform APIs. This means that it offers backward compatibility and is updated more frequently than the Android platform, making sure you always have access to the latest and greatest versions of the Jetpack components.

Android Jetpack is a collection of Android software components which helps us in building great Android apps.These software components help in:

  • Following the best practices and writing the boilerplate code.
  • Making complex things very simple.

Prior to Android Jetpack, we had many challenges during developing the android application:

  • Managing activity lifecycles in the application.
  • Surviving configuration changes.
  • Preventing memory leaks.

All these major problems have been solved by the Android Jetpack’s software components.

So, the solution for all the problems is Android Jetpack.

Another most important thing about the Jetpack is that it gets updated more frequently than the Android platform so that we always get the latest version.

Next question, We talk about a set of components, tools and guidance in Android Jetpack.

What is Android Jetpack Component ?

Android Jetpack components are a collection of libraries that are individually adoptable and built to work together while taking advantage of Kotlin language features that make us more productive.

These software components have been arranged in 4 categories which are as follows:

  • Foundation Components
  • Architecture Components
  • Behavior Components
  • UI Components

Let’s discuss one by one.

1. Foundation Components

Foundation components provide following cross-cutting functionality:

  • Backwards compatibility
  • Testing 
  • Kotlin language support.

All the foundation components are as follows:

  • App Compat: Degrade gracefully on older versions of Android with material design user interface implementation support.
  • Android KTX: Set of Kotlin extensions to write more concise, idiomatic Kotlin code.
  • Multidex: Provide support for multiple dex files for apps.
  • Test: A testing framework for unit and runtime UI tests in Android.

2. Architecture Components 

The architecture components help us in building:

  • Robust Apps
  • Testable Apps
  • Maintainable Apps

All the architecture components are as follows:

  • Data Binding: Declaratively bind UI elements to in our layout to data sources of our app.
  • Lifecycles: Manages activity and fragment lifecycles of our app.
  • LiveData: Notify views of any database changes.
  • Navigation: Handle everything needed for in-app navigation.
  • Paging: Gradually load information on demand from your data source.
  • Room: Fluent SQLite database access.
  • ViewModel: Manage UI-related data in a lifecycle-conscious way.
  • WorkManager: Manage every background jobs in Android with the circumstances we choose.

3. Behavior Components 

The behavior components help in the integration with standard Android services like:

  • Notifications
  • Permissions
  • Sharing
  • Assistant

All the behavior components are as follows:

  • Download Manager: Schedule and manage large downloads in background with auto retry support.
  • Media & playback: Backwards compatible APIs for media playback and routing (including Google Cast).
  • Notifications: Provides a backwards-compatible notification API with Wear and Auto support.
  • Permissions: Compatibility APIs for checking and requesting permissions in app.
  • Preferences: Create interactive settings screens for users to configure.
  • Sharing: Provides a share action suitable for an app’s action bar.
  • Slices: Create flexible UI elements that can display app data outside the app and can be extended all the way back to Android 4.4.

4. UI Components 

The UI components provide widgets and helpers to make your app not only easy, but delightful to use.

All the UI components are as follows:

  • Animation and transitions: Move widgets and transition between screens.
  • Auto: Components to develop Android Auto apps.
  • Emoji: Enable updated emoji font on older platforms.
  • Fragment: A basic unit of composable UI.
  • Layout: Lay out widgets with different algorithms.
  • Palette: Pull useful information from color palettes.
  • TV: Components to develop Android TV apps.
  • Wear: Components to develop Wear apps.

That’s all about Android Jetpack !!

Conclusion

In this article, We understood about the Android Jetpack Concepts. We learned the below Android Jetpack details:

  • What is Android Jetpack?
  • Why should we use ?
  • What Problem solves by Android Jetpack?
  • Types of Components in Android Jetpack
  • Components list and usage in Android Jetpack

Thanks for reading ! I hope you enjoyed and learned about the Android Jetpack Concepts. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING!!???

React Native – Understanding Direct Manipulation

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, we will learn about Direct Manipulation in React Native. Direct manipulation is an important concept in react native.

To understand the direct manipulation concept, we will discuss the below topics :

  • What is Direct Manipulation ?
  • How Direct Manipulation Works ?
  • UseCase using setState and setNativeProps

A famous quote about learning is :

” We now accept the fact that learning is a lifelong process of keeping abreast of change. And the most pressing task is to teach people how to learn.”

So, Let’s begin.


What is Direct Manipulation ?

The definition of Direct Manipulation says that 

Direct Manipulation is the process of making a component changes directly without using state/props or render whole hierarchies of components for a small change in one component.

Before the understanding of direct manipulation, we need to understand that how any components display on the UI Screen ?

The answer is that we need to write code for that components in render() method to display any component in the screen.

Now, what if you want to add/change any component?

The answer is we have to change state or props, otherwise the render() method will not be called. The render() method renders the whole component hierarchies even if there is a change in the only one component.

So the solution for this problem is Direct Manipulation that does not render all the component hierarchies for one component change.

In other way, we can say that

It is sometimes necessary to make changes directly to a component without using state/props to trigger a re-render of the entire subtree (or render the whole hierarchies of components for a small change in one component). This process is called Direct Manipulation.


How Direct Manipulation Works ?

In this section, we will see that how to work Direct Manipulation.

Direct Manipulation uses setNativeProps and Refs. setNativeProps is the react native equivalent to setting the properties directly on a DOM node.

and then, next question is “When to use setNativeProps and Refs ?”

Use setNativeProps when frequent re-rendering creates a performance bottleneck.

Direct manipulation will not be a tool that we reach for frequently; we will typically only be using it for creating continuous animations to avoid the overhead of rendering the component hierarchy and reconciling many views. setNativeProps is imperative and stores state in the native layer (DOM, UIView, etc.) and not within our React components, which makes our code more difficult to reason about. Before we use it, try to solve our problem with setState and shouldComponentUpdate.


UseCase

Let’s understand setNativeProps /Refs and setState concepts with one use case with the below code examples:

We have one TextInput which should be cleared when button is pressed.


1. Using setState

import React from 'react';
import {
  TextInput,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';

export default class App extends React.Component {

    constructor(props) {
      super(props)
      this.state = {
        inputText: '',
      }
    }
    clearText = () => {
        this.setState({
            inputText : ''
        })
    }

    render(){
        console.log("render method is called")
        return( 
        <View style={{justifyContent :'center',flex:1}}>
            <TextInput
            style={{height: 50,marginHorizontal: 20, borderWidth: 1, borderColor: '#ccf'}}
            value = {this.state.inputText}
            onChangeText= {(text) =>{
                this.setState({
                    inputText : text
                })
            }}
            />
            <TouchableOpacity onPress={()=>this.clearText()}>
                <Text>Clear Text</Text>
            </TouchableOpacity>
        </View>
        );
    }
}

In this above code example, we change the text or clear button each time. Render method is called which re-render the whole component even if there is a change for the component.


2. Using setNativeProps

import React from 'react';
import {
  TextInput,
  Text,
  TouchableOpacity,
  View,
} from 'react-native';

export default class App extends React.Component {

    constructor(props) {
      super(props)
      this.state = {
        text: '',
      }
    }

    clearText = () => {
      this._textInput.setNativeProps({
        text: ' '
      });
    }

    render(){
        return( 
        <View style={{justifyContent :'center',flex:1}}>
            <TextInput
            ref={component => { this._textInput = component}}
            style={{height: 40,marginHorizontal: 18, borderWidth: 1, borderColor: '#ccc'}}
            onChangeText= {(text) =>{
                this._textInput.setNativeProps({text: text});
            }}
            />

            <TouchableOpacity onPress={clearText}>
                <Text>Clear Text</Text>
            </TouchableOpacity>
        );
    }
}

In above code example, render method will not be called when we click on clear text button or text is changed.

So Here the component will not be re-rendered. We can change any props of a component using setProps and Refs without using re-render().

Some times If we update a property that is also managed by the render function, we might end up with some unpredictable and confusing bugs because anytime the component re-renders and that property changes, whatever value was previously set from setNativeProps will be completely ignored and overridden. So we need to avoid conflict with the render function.

By intelligently applying shouldComponentUpdate, we can avoid the unnecessary overhead involved in reconciling unchanged component subtrees, to the point where it may be performant enough to use setState instead of setNativeProps.

That’s all about in this article.


Conclusion

In this article, We understood about Direct Manipulation in React Native. We also discussed how Direct Manipulation works with use-case. In Summary, we can say that :

  • Direct Manipulation is the process of making a component changes directly without using state/props.
  • Direct Manipulation helps to prevent render all the component hierarchies for one component change.
  • Direct Manipulation uses setNativeProps and Refs when frequent re-rendering creates a performance bottleneck.

Thanks for reading ! I hope you enjoyed and learned about the Direct Manipulation concepts in React Native. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Android – How To Compare Valuable Constraint Layout With Relative Layout ?

Hello Readers, CoolMonkTechie heartily welcomes you in this article.

In this article, We will learn about Android Layouts Constraint Layout and Relative Layout differences. The differences between Constraint Layout and Relative Layout is the most common question asked in an interview with the experience android developer. This article will demonstrate the differences based on hierarchy, GUI builder and recomputing size and position of Constraint Layout rather than Relative Layout.

A famous quote about Learning is :

” The beautiful thing about learning is that nobody can take it away from you.”

So, Let’s begin.

Overview

By the definition of Constraint Layout,

” Constraint Layout is a view group that allows you to create large and complex layouts with a flat view hierarchy (no nested view groups). It’s similar to Relative Layout  in that all views are laid out according to relationships between sibling views and the parent layout, but it’s more flexible than RelativeLayout and easier to use with Android Studio’s Layout Editor.

and the definition of Relative Layout,

“Relative Layout is a view group that displays child views in relative positions. The position of each view can be specified as relative to sibling elements (such as to the left of or below another view) or in positions relative to the parent Relative Layout area (such as aligned to the bottom, left or center).”

We try to understand the differences between layouts with below diagrams :

In the diagram, Constraint layout has one layout means flat hierarchy, but Relative layout has nested layouts.

Nice !!

We can discuss the differences between Layouts as brief with the below points :


1. Flat View Hierarchy – No nested view groups

Constraint Layout has flat view hierarchy unlike other layouts, so it does a better performance than Relative Layout. It is the biggest advantage of constraint Layout, the only single layout can handle your UI. Where in the Relative layout, you need multiple nested layouts means (LinearLayout+RelativeLayout).


2. GUI Builder – Drag and drop functionality

In Android Studio you can drag and drop GUI component like TextView , Button , TextInputLayout etc. So now its make life easier to developers and make they work faster UI development and more productive so they continue improving drag-drop GUI builder. However drag-and-drop gestures, the developer is only providing you with X/Y coordinates of a widget, based on where you release the mouse button and completes the drop.

With RelativeLayout is difficult for GUI builder to handle drag-drop and probably you will have to dig inside the XML code to get things done.

But in ConstraintLayout, you have an option to constraint applying by the use of blueprint and visual editor tool which makes it easy to design a page.


3. Recomputing size and position

Each changes the detail of a widget often cause the sizes to have to be recomputed. 

Let’s take an example a change in EditText might starting point that a whole hierarchy to go through re-size and re-position work. If the application UI (user interface) has a container inside the container which is inside another container etc. Means that parents re-size or re-position their children and that can be very expensive (rework again on the user interface) for deep hierarchies.

So understanding the differences between the layouts, we can ask some questions related to layouts.


1. Does the ConstraintLayout have better performance than a nested Layout?

Yes, ConstraintLayout has designed with performance optimization in mind, more effective, easy use and trying to eliminate as many pass scenarios as possible. This is done by eliminating the deeply-nested view hierarchies with flat view hierarchy.


2. Can we replace RelativeLayout with ConstraintLayout completely?

Yes, you can completely replace RelativeLayout with ConstraintLayout.ConstraintLayout does all that RelativeLayout does, and more.


Conclusion

In this article, We understood the difference between Constraint Layout and Relative Layout in Android.  We conclude that

  • Constraint layout follows flat view hierarchy, but Relative layout has nested layouts.
  • This layout has an option to constraint applying by using blueprint and visual editor tool to design a page easily, but Relative layout is difficult for GUI builder to handle drag-drop and look up XML code to get things done.
  • Constraint layout uses flat view hierarchy so parent re-size or re-position their children can do easily, but Relative Layout can difficult and very expensive (rework again on the UI) for deep hierarchies.

Thanks for reading ! I hope you enjoyed and learned about Android Layouts Constraint Layout and Relative Layout differences. Reading is one thing, but the only way to master it is to do it yourself.

Please follow and subscribe us on this blog and and support us in any way possible. Also like and share the article with others for spread valuable knowledge.

If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.

Thanks again Reading. HAPPY READING !!???

Exit mobile version