Friday, July 3, 2015

RSNetworking 2

I would like to announce the release of RSNetworking 2 for Swift 2.  RSNetworking 2 has all the same great features that RSNetworking has but it was written to work with Swift 2.  RSNetworking and RSNetworking 2 are network libraries written entirely in the Swift programming language.  You can find RSNetworking 2 here:  https://github.com/hoffmanjon/RSNetworking2

Below lists the API that is exposed with RSNetworking 2

Classes
This section lists the classes that make up the RSNetworking API

RSTransaction
RSTransaction is the class that defines the transaction we wish to make. It exposes four properties, one initiator and one method.

Properties
  •   TransactionType - This defines the HTTP request method. Currently there are three types, GET, POST, UNKNOWN. Only the GET and POST actually sends a request.
  •   baseURL - This is the base URL to use for the request. This will normally look something like this: "https://itunes.apple.com". If you are going to a non-standard port you would put that here as well. It will look something like this: "http://mytestserver:8080"
  •   path - The path that will be added to the base url. This will normally be something like this: "search". It can also include a longer path string like: "path/to/my/service"
  •   parameters - Any parameters to send to the service.

Initiators
  •   init(transactionType: RSTransactionType, baseURL: String, path: String, parameters: [String: String]) - This will initialize the RSTransaction with all properties needed.

Functions
  •   getFullURLString() -> String - Builds and returns the full URL needed to connect to the service.

RSTransactionRequest
RSTransactionRequest is the class that builds and sends out the request to the service defined by the RSTransaction. It exposes four functions.

Functions
  •   dataFromRSTransaction(transaction: RSTransaction, completionHandler handler: RSNetworking.dataFromRSTransactionCompletionCompletionClosure): Retrieves an NSData object from the service defined by the RSTransaction. This is the main function and is used by the other three functions to retrieve an NSData object prior to converting it to the required format.
  •   stringFromRSTransaction(transaction: RSTransaction, completionHandler handler: RSNetworking.stringFromRSTransactionCompletionCompletionClosure): Retrieves an NSString object from the service defined by the RSTransaction. This function uses the dataFromRSTransaction function to retrieve an NSData object and then converts it to an NSString object.
  •   dictionaryFromRSTransaction(transaction: RSTransaction, completionHandler handler: RSNetworking.dictionaryFromRSTransactionCompletionCompletionClosure): Retrieves an NSDictionary object from the service defined by the RSTransaction. This function uses the dataFromRSTransaction function to retrieve an NSData object and then converts it to an NSDictionary object. The data returned from the URL should be in JSON format for this function to work properly.
  •   imageFromRSTransaction(transaction: RSTransaction, completionHandler handler: RSNetworking.imageFromRSTransactionCompletionCompletionClosure): Retrieves an UIImage object from the service defined by the RSTransaction. This function uses the dataFromRSTransaction function to retrieve an NSData object and then converts it to an UIImage object.

RSURLRequest
RSURLRequest will send a GET request to a service with just a URL. There is no need to define a RSTransaction to use this class. RSURLRequest exposes four functions.

Functions
  •   dataFromURL(url: NSURL, completionHandler handler: RSNetworking.dataFromURLCompletionClosure): Retrieves an NSData object from the URL passed in. This is the main function and is used by the other three functions to retrieve an NSData object prior to converting it to the required format
  •   stringFromURL(url: NSURL, completionHandler handler: RSNetworking.stringFromURLCompletionClosure): Retrieves an NSString object from the URL passed in. This function uses the dataFromURL function to retrieve an NSData object and then converts it to an NSString object.
  •   dictionaryFromJsonURL(url: NSURL, completionHandler handler: RSNetworking.dictionaryFromURLCompletionClosure): Retrieves an NSDictionary object from the URL passed in. This function uses the dataFromURL function to retrieve an NSData object and then converts it to an NSDictionary object. The data returned from the URL should be in JSON format for this function to work properly.
  •   imageFromURL(url: NSURL, completionHandler handler: RSNetworking.imageFromURLCompletionClosure): Retrieves an UIImage object from the URL. This function uses the dataFromURL function to retrieve an NSData object and then converts it to an UIImage object.

RSUtilities
RSUtilities will contain various utilities that do not have their own class. Currently there is only one function exposed by this class

Functions
  •   isNetworkAvailable(hostname: NSString) -> Bool - This function will check to see if the network is available. This is a class function.
  •   networkConnectionType(hostname: NSString) -> ConnectionType - This function will return the type of network connection that is available. The ConnectionType is an enum which can equal one of the following three types: NONETWORK, MOBILE3GNETWORK or WIFINETWORK.

Extensions
This section lists the extensions that RSNetworking adds to the Swift language

UIImageView
  •     setImageForURL(url: NSString, placeHolder: UIImage): Sets the image in the UIImageView to the placeHolder image and then asynchronously downloads the image from the URL. Once the image downloads it will replace the placeholder image with the downloaded image.
  •     setImageForURL(url: NSString): Asynchronously downloads the image from the URL. Once the image is downloaded, it sets the image of the UIImageView to the downloaded image.
  •     setImageForRSTransaction(transaction:RSTransaction, placeHolder: UIImage): Sets the image in the UIImageView to the placeHolder image and then asynchronously downloads the image from the RSTransaction. Once the image downloads it will replace the placeholder image with the downloaded image.
  •     setImageForRSTransaction(transaction:RSTransaction): Asynchronously downloads the image from the RSTransaction. Once the image downloads it sets the image of the UIImageView to the downloaded image.
UIButton  
  •     setButtonImageForURL(url: NSString, placeHolder: UIImage, state: UIControlState): Sets the background image of the UIButton to the placeholder image and then asynchronously downloads the image from the URL. Once the image downloads it will replace the placeHolder image with the downloaded image.
  •     setButtonImageForURL(url: NSString, state: UIControlState): Asynchronously downloads the image from the URL. Once the download is complete, it will set the background image of the UIButton to the downloaded image.
  •     setButtonImageForRSTransaction(transaction:RSTransaction, placeHolder: UIImage, state: UIControlState): Sets the background image of the UIButton to the placeHolder image and then asynchronously downloads the image from the URL. Once the image downloads it will replace the placeHolder image with the downloaded image.
  •     setButtonImageForRSTransaction(transaction:RSTransaction, state: UIControlState): Asynchronously downloads the image from the URL. Once the download is complete, it will set the background image of the UIButton to the downloaded image.

Sample Code
This section contains sample code that show how to use RSNetworking

RSURLRequest
dataFromURL
let client = RSURLRequest()

if let testURL = NSURL(string:"https://itunes.apple.com/search?term=jimmy+buffett&media=music") {

   client.dataFromURL(testURL, completionHandler: {(response : NSURLResponse!, responseData: NSData!, error: NSError!) -> Void in
      if let error = error {
          print("Error : \(error)")
      } else {
          let string = NSString(data: responseData, encoding: NSUTF8StringEncoding)
          print("Response Data: \(string)")
      }
   })
}

dictionaryFromJsonURL
let client = RSURLRequest()

if let testURL = NSURL(string:"https://itunes.apple.com/search?term=jimmy+buffett&media=music") {

  client.dictionaryFromJsonURL(testURL, completionHandler: {(response : NSURLResponse!, responseDictionary: NSDictionary!, error: NSError!) -> Void in
      if let error = error {
          print("Error : \(error)")
      } else {
          print("Response Dictionary: \(responseDictionary)")
      }
   })
}

stringFromURL
let client = RSURLRequest()

if let testURL = NSURL(string:"https://itunes.apple.com/search?term=jimmy+buffett&media=music") {

  client.stringFromURL(testURL, completionHandler: {(response : NSURLResponse!, responseString: NSString!, error: NSError!) -> Void in
      if let error = error {
          print("Error : \(error)")
      } else {
          print("Response Data: \(responseString)")
      }
   })
}

imageFromURL
let client = RSURLRequest()

if let imageURL = NSURL(string:"http://a1.mzstatic.com/us/r30/Music/y2003/m12/d17/h16/s05.whogqrwc.100x100-75.jpg") {

  client.imageFromURL(imageURL, completionHandler: {(response : NSURLResponse!, image: UIImage!, error: NSError!) -> Void in
      if let error = error {
          print("Error : \(error)")
      } else {
          self.imageView?.image = image;
      }
   })
}

RSUtilities
RSUtilities.isHostnameReachable
  if (RSUtilities.isNetworkAvailable("www.apple.com")) {
     print("reachable")
 } else {
     print("Not Reachable")
 }

UIImageView: setImageForURL
let imageURL = "http://a1.mzstatic.com/us/r30/Music/y2003/m12/d17/h16/s05.whogqrwc.100x100-75.jpg"
 
imageView.setImageForURL(imageURL, placeHolder: UIImage(named: "loading"))   

  or

let imageURL = "http://a1.mzstatic.com/us/r30/Music/y2003/m12/d17/h16/s05.whogqrwc.100x100-75.jpg"

self.imageView?.setImageForURL(imageURL)

UIButton: setImageForURL
let imageURL = "http://a1.mzstatic.com/us/r30/Music/y2003/m12/d17/h16/s05.whogqrwc.100x100-75.jpg"

button.setButtonImageForURL(url, placeHolder: UIImage(named: "loading"), state:.Normal)

  or

let imageURL = "http://a1.mzstatic.com/us/r30/Music/y2003/m12/d17/h16/s05.whogqrwc.100x100-75.jpg"

button.setButtonImageForURL(url, state:.Normal)

RSTransactionRequest
RSTransactionRequest is designed to be used when you need to create mulitple requests to the same service. It allows you to set up the request once and then just change the parameters for each request

dictionaryFromRSTransaction
let rsRequest = RSTransactionRequest()

//Create the initial request
let rsTransGet = RSTransaction(transactionType: RSTransactionType.GET, baseURL: "https://itunes.apple.com", path: "search", parameters: ["term":"jimmy+buffett","media":"music"])

rsRequest.dictionaryFromRSTransaction(rsTransGet, completionHandler: {(response : NSURLResponse!, responseDictionary: NSDictionary!, error: NSError!) -> Void in
    if let error = error {
        print("Error : \(error)")
    } else {
        print(responseDictionary)
    }
})


Now that you have the RSTransaction, you can simply change the parameters and make another request, if needed, like this:
 
let rsRequest = RSTransactionRequest()

//Create the initial request
rsTransGet.parameters = ["term":"Jimmy", "media":"music"]

rsRequest.dictionaryFromRSTransaction(rsTransGet, completionHandler: {(response : NSURLResponse!, responseDictionary: NSDictionary!, error: NSError!) -> Void in
    if let error = error {
        print("Error : \(error)")
    } else {
        print(responseDictionary)
    }
})

stringFromRSTransaction
 
//Change parameters from the previously example so we can make a second request
rsTransGet.parameters = ["term":"Jimmy", "media":"music"]
rsRequest.stringFromRSTransaction(rsTransGet, completionHandler: {(response : NSURLResponse!, responseString: NSString!, error: NSError!) -> Void in
    if let error = error {
        print("Error : \(error)")
    } else {
        print(responseString)
    }
})


If there is a feature that you would like to see in RSNetworking 2, please leave a comment to this blog post or in the github site here:  https://github.com/hoffmanjon/RSNetworking2.  If you would like to contribute to RSNetworking 2, please feel free to do so. 

Tuesday, June 30, 2015

Use Tuple types to model data

To use sqlite.swift with Swift 2, see the Create a Data Access Layer with SQLite.Swift and Swift 2 post.

A couple of weeks back I wrote a blog post on how to create a data access layer using SQLite.swift.  You can see the post here.  In one of the projects that I am currently working on, I wanted to create the data access layer as I described in that post because I know how well it worked from previous projects.  For this particular project however there are several tables that only have a couple of columns which means I needed to create a number of classes in the data model layer that contained only a few of properties. 

It seemed like a waste to create all those classes which only had a couple of properties so I started wondering if I could use tuples instead of classes to model my data.  I was unsure how modeling data with tuples would work but I decided to give it a try.  I found out that they really worked well. 

In this post I will explain how we could use tuples to model our data and then I will show how I would replace the data model classes from my previous post with tuples.  If you have not read my previous post about creating a data access layer with SQLite.swift, you can read it here.

What are tuple types

A Tuple type groups zero or more values into a single compound type.  Tuples can contain values of different types which allows us to group related data of different types together.  There are many uses for tuples and one of the most common is to use them as a return type from a function when we need to return multiple values.  The Void return type is actually a typealias for a tuple with no values.

Using tuple types to model our data

When I say that I want to model our data what I am referring to is grouping related data together is a single structure.  As an example if I want to create a class name PersonClass to model the information for a person the class may look like this:

class PersonClass {
    var firstName: String
    var lastName: String
    var age: Int
   
    init(firstName: String, lastName: String, age: Int) {
        self.firstName = firstName
        self.lastName = lastName
        self.age = age
    }
}

In this class we define three properties for our person and we also create an initializer that will set these properties.  This is quite a bit of code to simply store data.  If we wanted to create a typealias for a tuple named PersonTuple which models the same data, it would look like this:

typealias PersonTuple = (firstName: String, lastName: String, age: Int)

As we can see it takes a lot less code to create our PersonTuple tuple as compared to the PersonClass class.  Creating an instance of the PersonClass class is very similar to creating a PersonTuple variable.  The following code demonstrates this:

var pClass = PersonClass(firstName: "Jon", lastName: "Hoffman", age: 46)
var pTuple: PersonTuple = (firstName:"Jon", lastName:"Hoffman", age: 46)

We could actually shorten the tuple definition as shown in the following code but I prefer naming the parameters to show what they mean (really personal preference).

var pTuple: PersonTuple = ("Jon", "Hoffman", 46)

We can pass tuple types within our code just like we would pass an instance of a class or structure.  In the following code we show how to write a function that accepts an instance of the PersonClass as the only parameter and a function that accepts a PersonTuple as the only parameter.

func acceptPersonClass(person: PersonClass) {
    println("\(person.firstName) \(person.lastName)")
}
func acceptPersonTuple(person: PersonTuple) {
    println("\(person.firstName) \(person.lastName)")
}

When we replace data modeling classes or structures with tuples our code can become much more compact and in some ways easier to understand however we do lose the ability to add functionality to our data model types.  Some, including myself, would argue that losing the ability to add functions to our data model types is a good thing because if we truly want to separate our data model from our business logic we should not be embedding business logic in our data model classes.

Replacing data modeling classes with tuples

Tuples weren’t meant to be used as replacements for classes or structures however if we create a typealias of a tuple type it can very easily be used to model our data. In the Create a Data Access Layer using SQLite.swift post we had two classes in our data model layer:  Team.swift and Player.swift.  The code for these two classes is shown below:

Team.swift
import Foundation

class Team {
   
    var teamId: Int64?
    var city: String?
    var nickName: String?
    var abbreviation: String?
   
    init(teamId: Int64, city: String, nickName: String, abbreviation: String) {
       
        self.teamId = teamId
        self.city = city
        self.nickName = nickName
        self.abbreviation = abbreviation
    }
}

Player.swift
import Foundation

class Player {
   
    var playerId: Int64?
    var firstName: String?
    var lastName: String?
    var number: Int?
    var teamId: Int64?
    var position: Positions?
   
    init (playerId: Int64, firstName: String, lastName: String, number: Int, teamId: Int64, position: Positions?) {
        self.playerId = playerId
        self.firstName = firstName
        self.lastName = lastName
        self.number = number
        self.teamId = teamId
        self.position = position
    }
}

Now to replace these to classes with tuples, all I really need to do is to create typealiases instead.  For this I crate a DataModel.swift class that contains the following code:

typealias Team = (teamId: Int64?, city: String?, nickName: String?, abbreviation: String?)

typealias Player = (playerId: Int64?, firstName: String?, lastName: String?, number: Int?, teamId: Int64?, position: Positions?)

I then deleted the Team and Player classes and was able to build/run the project as it was before.  We could additionally remove the typealias names from the find() and findAll() methods of the data helper classes.  As an example, the findAll() method from the PlayerDataHelper class looks like this:

static func findAll() -> [T]? {
        var retArray = [T]()
        for item in table {
            retArray.append(Player(playerId: item[playerId], firstName: item[firstName], lastName: item[lastName], number: item[number], teamId: item[teamId], position: Positions(rawValue: item[position])))
        }
        return retArray
    }
We could change this function to this:

static func findAll() -> [T]? {
        var retArray = [T]()
        for item in table {
            retArray.append((playerId: item[playerId], firstName: item[firstName], lastName: item[lastName], number: item[number], teamId: item[teamId], position: Positions(rawValue: item[position])))
        }
        return retArray
    }

However I think the code reads better if we keep the typealias name in the code.

I created a github site which contains the sample project for the “Create a data access layer using SQLite.swift with the changes made in this post.  The repository is located here (https://github.com/hoffmanjon/SQLiteDataAccessLayer).  I would like to know what others think of using tuples to model data.  Please leave comments below.

If you would like to learn more about Swift, you can check out my book on amazon.com or on packtpub.com.


Saturday, June 27, 2015

Mastering Swift

Mastering Swift, the book I wrote on the Swift programming language, is about to be released by Packt Publishing.  The official release date is Tuesday June 30st, 2015.  You can order it from Packt’s site or from Amazon.  

I have always thought that you cannot master a programming language without a good understanding of the basics.  With that philosophy in mind this book starts with the basics of the Swift language before moving into more advance features and concepts.   With this structure, Mastering Swift will appeal to developers that are new to the Swift language because we cover the basics of the language and assume no prior knowledge of Swift.  Mastering Swift will also appeal to the experience developer because over half the books is spent on advance topics and concepts that are design to help the reader master the Swift programming language.

The fist five chapters will introduce the Swift programming language and will give the reader a good understanding of the Swift programming language.  the second half of the book will cover more advance topics such as concurrency, network development, design patterns and memory management including strong reference cycles.

This book takes a very code-centric approach to teaching the Swift programming language.   What this means is every feature and concept discussed in the book is backed by example code that is designed to demonstrate and reinforce the concept covered.  Details on how to download the sample code can be found in the preface of the book.


Below shows what is covered in each chapter:

Chapter 1, Taking our first steps with Swift, introduces the reader to the Swift programming language and will discuss what inspired Apple to create Swift. We will also go over the basic syntax of Swift.   We will also cover how to use Playgrounds to experiment and test Swift code.
Chapter 2, Learning Variables, Constants, Strings, and Operators, explains to the reader about variables and constants in Swift and how to use each of them. There will be brief overviews of the most common variable types with examples on how to use them. We will conclude this chapter by covering the most common operators in the Swift language.
Chapter 3, Using Collections and Cocoa Data Types, introduces Swift's Array and Dictionary collection types with examples on how to use them. We will also show how to use Cocoa and Foundation data types with Swift.
Chapter 4, Learning about Control Flow and Functions, explains how to use Swift's control flow statements. These include looping, conditional, and control transfer statements. The second half of the chapter is all about functions and how to use them.
Chapter 5, Understanding Classes and Structures, explains Swift's classes and structures in detail. We will look at what make them similar and what makes them different. We will also look at access controls and object-oriented design. We will conclude this chapter by looking at memory management in Swift.
Chapter 6, Working with XML and JSON Data, starts off by discussing what XML and JSON data are and their uses. We will then show several examples of how to parse and build XML and JSON data using Apple's frameworks.
Chapter 7, Custom Subscripting, examines what subscripts are and how we can add custom subscripts in our classes, structures, and enumerations.  We will look at the proper way to use subscripts and also when not to use subscripts.
Chapter 8, Using Optional Types and Optional Chaining, looks at what optional types really are, various ways to unwrap them, and optional chaining.  We do introduce the Optional type in earlier chapters but this chapter is designed to give the reader a complete understanding of them.  
Chapter 9, Working with Generics, allows us to write very flexible and reusable code that avoids duplication. In this chapter, we will examine how Swift implements generics. We will also examine the proper ways to use generics and examples of how not to use generics.
Chapter 10, Working with Closures, examines how to define and use closures in our code. We will conclude this chapter with a section on how to avoid strong reference cycles with closures.
Chapter 11, Using Mix and Match, examines how to include Swift code in our Objective-C projects and Objective-C code in our Swift projects.
Chapter 12, Concurrency and Parallelism in Swift, starts off by discussing the difference between concurrency and parallelism.  We then shows how to use both Grand Central Dispatch (GCD) and Operation Queues to add concurrency and parallelism to our applications.
Chapter 13, A Swift Formatting Style Guide, defines a style guide for the Swift language that can be a template for enterprise developers that need to create a style guide.
Chapter 14, Network development with Swift, looks at the Apple API's to connect to remote severs and how to best use them.  We also examine the RSNetworking framework on how to use it in our projects
Chapter 15, Adopting Design Patterns in Swift, looks at what design patterns are and why we should use them.  We also examine how to implement some of the more common design patterns in Swift.  

I would like to thank everyone at Packt Publishing who helped with this book.  Without their help and commitment to this book it would not have turned out so awesome and believe me I really think it turned out awesome.  So if you are new to the Swift programming language or an experience developer that is looking to take their skills to the next level, Mastering Swift may be just the book for you.  Once you have checked out the book, please continue to come back to this blog as I expand and enhance on the material in the book.