Book Image

iOS Programming Cookbook

Book Image

iOS Programming Cookbook

Overview of this book

Do you want to understand all the facets of iOS programming and build complex iOS apps? Then you have come to the right place. This problem-solution guide will help you to eliminate expensive learning curves and focus on specific issues to make you proficient at tasks and the speed-up time involved. Beginning with some advanced UI components such as Stack Views and UICollectionView, you will gradually move on to building an interface efficiently. You will work through adding gesture recognizer and touch elements on table cells for custom actions. You will work with the Photos framework to access and manipulate photos. You will then prepare your app for multitasking and write responsive and highly efficient apps. Next, you will integrate maps and core location services while making your app more secure through various encryption methods. Finally, you will dive deep into the advanced techniques of implementing notifications while working with memory management and optimizing the performance of your apps. By the end of the book, you will master most of the latest iOS 10 frameworks.
Table of Contents (22 chapters)
iOS Programming Cookbook
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Working with memory management and ARC


If you are coming from the old school where MRC (Manual Reference Counting) was being used for memory management, you definitely know how much headache developers suffer to manage memory in iOS. With iOS 5, Apple introduced ARC (Automatic Reference Counting), and life became easier in terms of memory management. Though ARC manages your memory automatically, some mistakes may ruin your memory with no mercy if you didn't understand the concept of memory management.

Getting ready

Before checking how to manage memory and avoid some common mistakes, I would like to highlight some notes:

  • Assigning a class instance to variable, constant, or properties will create a strong reference to this instance. The instance will be kept in memory as long as you use it.

  • Setting the reference to nil will reduce its reference counting by one (once it reaches zero, it will be deallocated from memory). When your class deallocated from memory, all class instance properties will be set to nil as well.

How to do it...

  1. Create two classes, Person and Dog, with a relation between them, as shown in the following code snippet (this code snippet has a memory issue called reference cycle):

          class Dog{
            var name: String
            var owner: Person!
            init(name: String){
              self.name = name
            }
          }
          class Person{
            var name: String
            var id: Int
            var dogs = [Dog]()
            init(name: String, id: Int){
              self.name = name
              self.id = id
            }
          }
          let john = Person(name: "John", id: 1)
          let rex = Dog(name: "Rex")
          let rocky = Dog(name: "Rocky")
          john.dogs += [rex, rocky] // append dogs
          rex.owner = john
          rocky.owner = john
    
  2. Update the reference type of owner property in the Dog class to break this cycle:

          class Dog{
            var name: String
            weak var owner: Person!
            init(name: String){
            self.name = name
          }
        }

How it works...

We have started our example by creating two classes, Person and Dog. The Person class has one-to-many relation to the Dog class via the property array dogs. The Dog class has one-to-one relation to class Person via the property owner. Everything looks good, and it works fine if you tested, but unfortunately we did a terrible mistake. We have a retain cycle problem here, which means we have two objects in memory; each one has a strong reference to the other. This leads to a cycle that prevents both of them from being deallocated from memory.

This problem is a common problem in iOS, and not all developers note it while coding. We call it as parent-child relation. Parent (in our case, it's the Person class) should always have a strong reference to child (the Dog class); child should always have a weak reference to the parent. Child doesn't need to have strong reference to parent, as child should never exit when parent is deallocated from memory.

To solve such a problem, you have to break the cycle by marking one of these references as weak. In step 2, we see how we solved the problem by marking the property owner as weak.

There's more...

The reference cycle problem can happen in situations other than relations between classes. When you use closure, there is a case where you may face a retain cycle. It happens when you assign a closure to a property in class instance and then this closure captures the instance. Let's consider the following example:

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 
    } 
} 
 
let heading = HTMLElement(name: "h1", text: "h1 title") 
print(heading.asHTML()) // <h1>h1 title</h1> 

We have the HTMLElement class, which has closure property asHTML. Then, we created an instance of that class which is heading, and then we called the closure to return HTML text. The code works fine, but as we said, it has a reference cycle. The instance set closure to one of its property, and the closure captures the instance (happens when we call self.name and self.text inside the closure). The closure in that case will retain self (have a strong reference to the heading instance), and at the same time, heading already has a strong reference to its property asHTML. To solve reference cycle made with closure, add the following line of code as first line in closure:

[unownedself] in 

So, the class will look like this:

class HTMLElement { 
 
let name: String 
let text: String? 
 
lazy var asHTML: () -> String = { 
 
        [unownedself] 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 
    } 
} 

The unowned keyword informs the closure to use a weak reference to self instead of the strong default reference. In that case, we break the cycle and everything goes fine.