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 protocols and delegates


Protocol is a set of methods and properties for a particular task to which classes, structure, or enumeration can be conformed.

Getting ready

The syntax of protocol goes like this:

protocol ProtocolName{ 
   // List of properties and methods goes here.... 
} 

The keyword protocol followed by the protocol name and curly braces are the building blocks of any protocol you need to write. Classes, structures, or enumeration can then conform to it like this:

class SampleClass: ProtocolName{ 
} 

After class name, you type colon and the super class name that this class extend from if any, followed by a list of protocols that you want to conform to with a comma separation.

How to do it...

  1. Create a new playground file in Xcode called Protocols as usual.

  2. Complete the following example using the following protocol:

          protocol VehicleProtocol{ 
            // properties 
            var name: String {set get} // settable and gettable 
            var canFly: Bool {get} // gettable only (readonly) 
        
            // instance methods 
            func numberOfWheels() ->Int 
            func move() 
            func stop() 
        
            // class method 
            staticfuncpopularBrands() -> [String] 
          } 
     
          class Bicycle: VehicleProtocol{ 
            var name: String 
            var canFly: Bool{ 
              return false 
          } 
        
          init(name: String){ 
          self.name = name 
          } 
        
          func numberOfWheels() -> Int { 
            return 2 
          } 
          func move() { 
           // move logic goes here 
          } 
          func stop() { 
           // stop logic goes here 
          } 
          static func popularBrands() -> [String] { 
            return ["Giant", "GT", "Marin", "Trek", "Merida", "Specialized"] 
          } 
        } 
     
        class Car: VehicleProtocol{ 
          var name: String 
          var canFly: Bool{ 
            return false 
          } 
        
        init(name: String){ 
          self.name = name 
        } 
        
        funcnumberOfWheels() ->Int { 
          return 4 
        } 
        func move() { 
          // move logic goes here 
        } 
        func stop() { 
          // stop logic goes here 
        } 
        static func popularBrands() -> [String] { 
          return ["Audi", "BMW", "Honda", "Dodge", "Lamborghini", "Lexus"] 
        } 
      } 
     
      let bicycle1 = Bicycle(name: "Merida 204") 
      bicycle1.numberOfWheels() // 2 
     
      let car1 = Car(name: "Honda Civic") 
      car1.canFly  // false 
     
      Bicycle.popularBrands() // Class function 
      // ["Giant", "GT", "Marin", "Trek", "Merida", "Specialized"] 
      Car.popularBrands() // ["Audi", "BMW", "Honda", "Dodge", "Lamborghini", "Lexus"] 
    

How it works...

We started by defining VehicleProtocol that has a list of properties and functions that every vehicle should have. In properties, we have two types of properties: name, which is marked as {get set}, and canFly, which is marked as {get}. When you mark a property {get set}, it means it's gettable and settable, whereas {get} means it only gettable, in other words, it's a read-only property. Then, we added four methods, out of which three methods-numberOfWheels(), move(), and stop()-are instance methods. The last one-popularBrands()- marked as static is a type method. Types methods can be called directly with type name, and there is no need to have instance to call it.

Then, we created two new classes, Bicycle and Car, which conform to VehicleProtocol, and each one will have different implementations.

There's more...

We have already covered the most important parts of protocols and how to use it, but still they have more features, and there are many things that can be done with it. We will try here to mention them one by one to see when and how we can use them.

Mutating methods

Swift allows you mark protocol methods as mutating when it's necessary for these methods to mutate (modify) the instance value itself. This is applicable only in structures and enumerations; we call them value types. Consider this example of using mutating:

protocol Togglable{ 
   mutating func toggle() 
} 
 
enum Switch: Togglable{ 
   case ON 
   case OFF 
    
   mutating func toggle() { 
       switch self { 
       case .ON: 
           self = OFF 
       default: 
           self = ON 
       } 
   } 
} 

The Switch enum implements the method toggle, as it's defined in the protocol Togglable. Inside toggle(), we could update self-value as function marked as mutating.

Delegation

Delegation is the most commonly used design pattern in iOS. In delegation, you enable types to delegate some of its responsibilities or functions to another instance of another type. To create this design pattern, we use protocols that will contain the list of responsibilities or functions to be delegated. We usually use delegation when you want to respond to actions or retrieve or get information from other sources without needing to know the type of that sources, except that they conform to that protocol. Let's take a look at an example of how to create use delegate:

@objc protocol DownloadManagerDelegate { 
   func didDownloadFile(fileURL: String, fileData: NSData) 
   func didFailToDownloadFile(fileURL: String, error: NSError) 
} 
class DownloadManager{ 
   weak var delegate: DownloadManagerDelegate! 
   func downloadFileAtURL(url: String){ 
       // send request to download file 
       // check response and success or failure 
       if let delegate = self.delegate { 
           delegate.didDownloadFile(url, fileData: NSData()) 
       } 
   } 
} 
 
class ViewController: UIViewController, DownloadManagerDelegate{ 
   func startDownload(){ 
       letdownloadManager = DownloadManager() 
       downloadManager.delegate = self 
   } 
    
   func didDownloadFile(fileURL: String, fileData: NSData) { 
       // present file here 
   } 
   func didFailToDownloadFile(fileURL: String, error: NSError) { 
        // Show error message 
   } 
} 

The protocol DownloadManagerDelegate contains methods that would be called once the specific actions happen to inform the class that conforms to that protocol. The DownloadManager class performs the download tasks asynchronously and informs the delegate with success or failure after it's completed. DownloadManager doesn't need to know which object will use it or any information about it. The only thing it cares about is that the class should conform to the delegate protocol, and that's it.

Class-only protocols

We mentioned before that classes, structures, and enumerations could adopt protocols. The difference among them is that classes are reference types, whereas structures and enumerations are value types. If you find yourself having some specific actions that will be done only via reference types, mark it as class only. To do so, just mark it as follows:

protocol ClassOnlyProtocol: class{ 
   // class only properties and methods go here 
} 

Add a colon : and the class keyword to mark your protocol as class only.

Checking protocol conformance

It would be very useful to check whether an object conforms to a specific protocol or not. It's very useful when you have a list of objects, and only some of them conform to specific protocol. To check for protocol conformance, do the following:

class Rocket{ 
} 
 
var movingObjects = [Bicycle(name: "B1"), Car(name:"C1"), Rocket()] 
 
for item in movingObjects{ 
   if let vehicle =  item as? VehicleProtocol{ 
       print("Found vehcile with name \(vehicle.name)") 
       vehicle.move() 
   } 
   else{ 
       print("Not a vehcile") 
   } 
} 

We created a list of objects, and some of them conform to VehicleProtocol that we created earlier. Inside the for-loop we casted each item to VehicleProtocol inside if statement; the cast will succeed only if this item already conforms to that protocol.

Optional requirements

You see that when you list your properties and methods in a protocol, the type that conforms to that protocol should adopt to all properties and methods. Skipping one of them will lead to a compiler error. Some protocols may contain methods or properties that are not necessary to implement, especially with delegates. Some delegate methods are meant to notify you something that you don't care about. In that case, you can mark these methods as optional. The keyword optional can be added before properties and methods to mark them as optional. Another thing, the protocol that has optional stuff should be marked with @Objc. Take a look at the following example:

@objc protocol DownloadManagerDelegate { 
   func didDownloadFile(fileURL: String, fileData: NSData) 
   optional func didFailToDownloadFile(fileURL: String, error: NSError) 
} 

It's the new version of DownloadManagerDelegate, which marks didFailToDownloadFile method as optional.