Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
iOS Programming Cookbook

You're reading from   iOS Programming Cookbook Over 50 exciting and powerful recipes to help you unearth the promise of iOS programming

Arrow left icon
Product type Paperback
Published in Mar 2017
Publisher Packt
ISBN-13 9781786460981
Length 520 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Toc

Table of Contents (16) Chapters Close

Preface 1. Swift Programming Language FREE CHAPTER 2. The Essentials 3. Integrating with Messages App 4. Working with Interface Builder 5. Working with UITableView 6. Animations and Graphics 7. Multimedia 8. Concurrency 9. Location Services 10. Security and Encryption 11. Networking 12. Persisting Data with Core Data 13. Notifications 14. App Search 15. Optimizing Performance

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.

You have been reading a chapter from
iOS Programming Cookbook
Published in: Mar 2017
Publisher: Packt
ISBN-13: 9781786460981
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime