On June 2nd, 2014, Apple unveiled a brand – new object-oriented programming language: Swift, a replacement for Objective-C, which had been up to that point the standard programming language for OS X and iOS application development.

It was a bold move to outright change the main development language for such a popular platform; even so, our team responded to this news with huge enthusiasm and decided to switch to it in short order. And we’re not the only ones: Swift has received glowing praise for its simplicity and flexibility, and its adoption rate has skyrocketed.

After developing a couple of iOS applications with Swift, we decided to share our thoughts about some of the things we think make it easier and more enjoyable to program with. So here’s our top ten list of the biggest and most important differences between Swift and Objective-C!

(Feel free to use a playground to practice with the code snippets in this article. It’s always a good idea to explore new languages and frameworks!)

Swift vs. Objective-C: 10 Differences

1. Optionals

2. Control Flow

3. Type Inference

4. Tuples

5. String Manipulation

6. Guard and Defer

7. Functional Programming Patterns

8. Enumerations

9. Functions

10. Do Statement

1. Optionals

Optionals are a concept which doesn’t exist in C or Objective-C. They allow functions which may not always be able to return a meaningful value (e.g. in the event of invalid input) to return either a value encapsulated in an optional or nil. In C and Objective-C, we can already return nil from a function that would normally return an object, but we don’t have this option for functions which are expected to return a basic type such as int, float, or double. Observe:

let a = "512" let b = Int(a) print(b) // Optional(512) 1 2 3 4 5 let a = "512" let b = Int ( a ) print ( b ) // Optional(512)

The Int function in this case returns an optional containing the int value 512, as expected. But what happens if we try to convert something like “Hello” instead? In that case, the function will return nil, as explained above:

let a = "Hello" let b = Int(a) print(b) // nil 1 2 3 4 5 let a = "Hello" let b = Int ( a ) print ( b ) // nil

As you may already know, in Objective-C, if you call a method on a nil pointer, nothing happens. No compile errors, no runtime errors, nothing. This is a well-known source of bugs and unexpected behavior, and overall frustration: the lack of feedback means developers are forced to hunt down the source of these errors all on their own.

With Swift, you don’t have worry about this:

var x = Int("555") print(x.successor()) // error 1 2 3 4 var x = Int ( "555" ) print ( x . successor ( ) ) // error

The compiler itself will raise an error, since x right now is an optional and could potentially be nil. Before using an optional value, you need to unwrap it like so:

var x = Int("555") if x != nil { print(x!.successor()) // 556 } 1 2 3 4 5 6 var x = Int ( "555" ) if x != nil { print ( x ! . successor ( ) ) // 556 }

Alternately, we can use optional binding:

var x = Int("555") if var y = x { y += 445 print(y) // 1000 } 1 2 3 4 5 6 7 var x = Int ( "555" ) if var y = x { y += 445 print ( y ) // 1000 }

2. Control Flow

Anyone who’s programmed in C or a C-like language is familiar with the use of curly braces ({}) to delimit code blocks. In Swift, however, they’re not just a good idea: they’re the law!

if a < 5 { print("Something") } 1 2 3 4 5 if a < 5 { print ( "Something" ) }

This will raise a compiler error in Swift!

if a < 5 print(“Something") 1 2 3 4 if a < 5 print ( “ Something " )

Unlike Objective-C, Swift treats curly braces as mandatory for if, for, while, and repeat statements. This might not sound like an improvement over Objective-C per se, but consider that even Apple’s own developers have had trouble without curly braces to keep them in line:

if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; 1 2 3 4 5 if ( ( err = SSLHashSHA1 . update ( & hashCtx , & signedParams ) ) != 0 ) goto fail ; goto fail ;

That’s right: the infamous iOS “goto fail” error could have been avoided if Objective-C was as strict as Swift about enforcing curly braces!

3. Type Inference

Swift introduces type safety to iOS development. Once a variable is declared with a particular type, its type is static and cannot be changed. The compiler is also smart enough to figure out (or infer) what type your variables should be based on the values you assign them:

var str = "Some string" // OR var str2:String str2 = "Other string" 1 2 3 4 5 6 var str = "Some string" // OR var str2 : String str2 = "Other string"

This also means the compiler will raise an error if you try to assign a numeric value, such as 10, to our str2 variable:

str2 = 10 // error: Cannot assign value of type 'Int' to type 'String' 1 2 3 str2 = 10 // error: Cannot assign value of type 'Int' to type 'String'

Compare Objective-C, where you must always state a variable’s type explicitly:

NSString str = @"There is no type inference in Objective-C :(" 1 2 3 NSString str = @ "There is no type inference in Objective-C :("

4. Tuples

Swift supports tuples, values which store groups of other values. Unlike arrays, the values in a tuple don’t have to all be the same type. For example, you can have a tuple of Strings and Ints:

var t:(String, Int) = ("John", 33) print(t.0, t.1) var j:(name:String, Int) = ("Morgan", 52) print(j.name, j.1) 1 2 3 4 5 6 7 var t : ( String , Int ) = ( "John" , 33 ) print ( t . 0 , t . 1 ) var j : ( name : String , Int ) = ( "Morgan" , 52 ) print ( j . name , j . 1 )

The most obvious use for tuples is returning multiple values from a function:

var arr = [23, 5, 7, 33, 9] func findPosition(el:Int, arr:[Int]) -> (found:Bool, position:Int)? { if arr.isEmpty { return nil } for (i, value) in arr.enumerate() { if value == el { return (true, i) } } return (false, -1) } if let (isFound, elPosition) = findPosition(5, arr: arr) { print(isFound, elPosition) // true 1 } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 var arr = [ 23 , 5 , 7 , 33 , 9 ] func findPosition ( el : Int , arr : [ Int ] ) -> ( found : Bool , position : Int ) ? { if arr . isEmpty { return nil } for ( i , value ) in arr . enumerate ( ) { if value == el { return ( true , i ) } } return ( false , - 1 ) } if let ( isFound , elPosition ) = findPosition ( 5 , arr : arr ) { print ( isFound , elPosition ) // true 1 }

In Objective-C, we can use blocks in similar fashion, but it’s not as straightforward or elegant.

5. String Manipulation

Swift offers huge improvements over Objective-C in terms of string manipulation. For starters, you don’t have to worry about mutable vs. immutable strings anymore: just declare your string with var if you want to change it in the future, or with let if you need it to remain constant.

String concatenation is as easy as 1+1=2:

// Swift: var str = "My string" str += " and another string” 1 2 3 4 5 // Swift: var str = "My string" str += " and another string ”

Compare Objective-C, where concatenating two immutable strings requires you to create an entirely new NSString object. Here’s an example using the “stringWithFormat” method:

// Obj-C: NSString *myString = @"My string"; myString = [NSString stringWithFormat:@"%@ and another string", myString]; 1 2 3 4 5 // Obj-C: NSString * myString = @ "My string" ; myString = [ NSString stringWithFormat : @ "%@ and another string" , myString ] ;

As you can see here, string formatting in Objective-C involves inserting special placeholders for each different data type we want to interpolate into our string:

NSString *str = [NSString stringWithFormat:@"String: %@ | Signed 32-bit integer: %d | 64-bit floating-point number: %f", @"My String", myInt, myFloat]; 1 2 3 NSString * str = [ NSString stringWithFormat : @ "String: %@ | Signed 32-bit integer: %d | 64-bit floating-point number: %f" , @ "My String" , myInt , myFloat ] ;

In Swift, we can instead interpolate values by inserting the variable names directly into our string:

var str = "String: \(myString) | Signed 32-bit integer: \(myInt) | 64-bit floating-point number: \(myFloat)" 1 2 3 var str = "String: \ ( myString ) | Signed 32-bit integer: \ ( myInt ) | 64-bit floating-point number: \ ( myFloat ) "

6. Guard And Defer

Ever heard of the “pyramid of doom”? If not, here’s a snippet of Objective-C code that should jog your memory:

enum TriangleAreaCalcError: ErrorType { case AngleNotSpecified case InvalidAngle case SideANotSpecified case SideBNotSpecified } func calcTriangleArea(a: Double ? , b : Double ? , alpha : Double ? ) throws - > Double { if let a = a { if let b = b { if let alpha = alpha { if alpha < 180 && alpha >= 0 { if alpha == 180 { return 0 } return 0.5 * a * b * sin(alpha * M_PI / 180.0) } else { throw TriangleAreaCalcError.InvalidAngle } } else { throw TriangleAreaCalcError.AngleNotSpecified } } else { throw TriangleAreaCalcError.SideBNotSpecified } } else { throw TriangleAreaCalcError.SideANotSpecified } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 enum TriangleAreaCalcError : ErrorType { case AngleNotSpecified case InvalidAngle case SideANotSpecified case SideBNotSpecified } func calcTriangleArea ( a : Double ? , b : Double ? , alpha : Double ? ) throws - > Double { if let a = a { if let b = b { if let alpha = alpha { if alpha < 180 && alpha >= 0 { if alpha == 180 { return 0 } return 0.5 * a * b * sin ( alpha * M_PI / 180.0 ) } else { throw TriangleAreaCalcError . InvalidAngle } } else { throw TriangleAreaCalcError . AngleNotSpecified } } else { throw TriangleAreaCalcError . SideBNotSpecified } } else { throw TriangleAreaCalcError . SideANotSpecified } }

Now that’s a pyramid that would make even Indiana Jones blink! Fortunately, in Swift, we have guard, a new conditional statement which can make this code much more readable. Guard stops program flow if a condition is not met:

func calcTriangleArea(a: Double ? , b : Double ? , alpha : Double ? ) throws - > Double { guard let a = a else { throw TriangleAreaCalcError.SideANotSpecified } guard let b = b else { throw TriangleAreaCalcError.SideBNotSpecified } guard let alpha = alpha else { throw TriangleAreaCalcError.AngleNotSpecified } if alpha == 180 { return Double(0) } guard alpha < 180 && alpha >= 0 else { throw TriangleAreaCalcError.InvalidAngle } return 0.5 * a * b * sin(alpha * M_PI / 180.0) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 func calcTriangleArea ( a : Double ? , b : Double ? , alpha : Double ? ) throws - > Double { guard let a = a else { throw TriangleAreaCalcError . SideANotSpecified } guard let b = b else { throw TriangleAreaCalcError . SideBNotSpecified } guard let alpha = alpha else { throw TriangleAreaCalcError . AngleNotSpecified } if alpha == 180 { return Double ( 0 ) } guard alpha < 180 && alpha >= 0 else { throw TriangleAreaCalcError . InvalidAngle } return 0.5 * a * b * sin ( alpha * M_PI / 180.0 ) }

Swift also gives us the defer keyword, which provides a safe and easy way to handle code which we want executed only when the program leaves the current scope:

func someImageFunc() - > UIImage ? { let dataSize: Int = ... let destData = UnsafeMutablePointer < UInt8 > .alloc(dataSize) // ... guard error else { destData.dealloc(dataSize) // #1 return nil } guard error2 else { destData.dealloc(dataSize) // #2 return nil } guard error3 else { destData.dealloc(dataSize) // #3 return nil } destData.dealloc(dataSize) // #4 // ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 func someImageFunc ( ) - > UIImage ? { let dataSize : Int = . . . let destData = UnsafeMutablePointer < UInt8 > . alloc ( dataSize ) // ... guard error else { destData . dealloc ( dataSize ) // #1 return nil } guard error2 else { destData . dealloc ( dataSize ) // #2 return nil } guard error3 else { destData . dealloc ( dataSize ) // #3 return nil } destData . dealloc ( dataSize ) // #4 // ... }

As you can see, we need to write four separate calls to destData.dealloc(dataSize) to make sure our pointer gets deallocated even if guard makes the function exit in the event of an error. With defer, we have a hassle-free way to clean up both our pointer and our code:

func someImageFunc() - > UIImage ? { let dataSize: Int = ... let destData = UnsafeMutablePointer < UInt8 > .alloc(dataSize) // ... defer { destData.dealloc(dataSize) } guard error else { return nil } guard error2 else { return nil } guard error3 else { return nil } // ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 func someImageFunc ( ) - > UIImage ? { let dataSize : Int = . . . let destData = UnsafeMutablePointer < UInt8 > . alloc ( dataSize ) // ... defer { destData . dealloc ( dataSize ) } guard error else { return nil } guard error2 else { return nil } guard error3 else { return nil } // ... }

7. Functional Programming Patterns

Swift incorporates a number of functional programming features, such as map and filter, which can be used on any collection which implements the CollectionType protocol:

let a = [4, 8, 16] print(a.map{$0 / 2}) // [2, 4, 8] let a:[(name:String, area:String)] = [("John", "iOS"), ("Sam", "Android"), ("Paul", "Web")] let b = a.map({"Developer \($0.name) (\($0.area))"}) // ["Developer John (iOS)", "Developer Sam (Android)", "Developer Paul (Web)”] let a = [23, 5, 7, 12, 10] let b = a.filter{$0 > 10} print(b) // [23, 12] let sum = (20...30) .filter { $0 % 2 != 0 } .map { $0 * 2 } .reduce(0) { $0 + $1 } print(sum) // 250 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 let a = [ 4 , 8 , 16 ] print ( a . map { $ 0 / 2 } ) // [2, 4, 8] let a : [ ( name : String , area : String ) ] = [ ( "John" , "iOS" ) , ( "Sam" , "Android" ) , ( "Paul" , "Web" ) ] let b = a . map ( { "Developer \ ( $ 0 . name ) ( \ ( $ 0 . area ) )" } ) // ["Developer John (iOS)", "Developer Sam (Android)", "Developer Paul (Web)”] let a = [ 23 , 5 , 7 , 12 , 10 ] let b = a . filter { $ 0 > 10 } print ( b ) // [23, 12] let sum = ( 20...30 ) . filter { $ 0 % 2 != 0 } . map { $ 0 * 2 } . reduce ( 0 ) { $ 0 + $ 1 } print ( sum ) // 250

Objective-C has no built-in support for functional programming. To use these same kinds of functions, you would have to use a third-party library.

8. Enumerations

In Swift, enumerations are more powerful than they ever were in Objective-C: they can now contain methods and be passed by value. Here’s a little snippet of code which nicely illustrates how enums work in Swift:

enum Location { case Address(city: String, street: String) case Coordinates(lat: Float, lon: Float) func printOut() { switch self { case let.Address(city, street): print("Address: " + street + ", " + city) case let.Coordinates(lat, lon): print("Coordiantes: (\(lat), \(lon))") } } } let loc1 = Location.Address(city: "Boston", street: "33 Court St") let loc2 = Location.Coordinates(lat: 42.3586, lon: -71.0590) loc1.printOut() // Address: 33 Court St, Boston loc2.printOut() // Coordiantes: (42.3586, -71.059) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 enum Location { case Address ( city : String , street : String ) case Coordinates ( lat : Float , lon : Float ) func printOut ( ) { switch self { case let . Address ( city , street ) : print ( "Address: " + street + ", " + city ) case let . Coordinates ( lat , lon ) : print ( "Coordiantes: ( \ ( lat ) , \ ( lon ) )" ) } } } let loc1 = Location . Address ( city : "Boston" , street : "33 Court St" ) let loc2 = Location . Coordinates ( lat : 42.3586 , lon : - 71.0590 ) loc1 . printOut ( ) // Address: 33 Court St, Boston loc2 . printOut ( ) // Coordiantes: (42.3586, -71.059)

Enums can also be recursive, so we can build a linked list using the indirect statement, which tells the compiler to add the necessary layer of indirection:

enum List { case Empty indirect case Cell(value: Int, next: List) } let list0 = List.Cell(value: 1, next: List.Empty) let list1 = List.Cell(value: 4, next: list0) let list2 = List.Cell(value: 2, next: list1) let list3 = List.Cell(value: 6, next: list2) let headL = List.Cell(value: 3, next: list3) func evaluateList(list: List) - > Int { switch list { case let.Cell(value, next): return value + evaluateList(next) case .Empty: return 0 } } print(evaluateList(headL)) // 16 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 enum List { case Empty indirect case Cell ( value : Int , next : List ) } let list0 = List . Cell ( value : 1 , next : List . Empty ) let list1 = List . Cell ( value : 4 , next : list0 ) let list2 = List . Cell ( value : 2 , next : list1 ) let list3 = List . Cell ( value : 6 , next : list2 ) let headL = List . Cell ( value : 3 , next : list3 ) func evaluateList ( list : List ) - > Int { switch list { case let . Cell ( value , next ) : return value + evaluateList ( next ) case . Empty : return 0 } } print ( evaluateList ( headL ) ) // 16

9. Functions

Swift’s function syntax is flexible enough to define anything from a simple C-style function to a complex Objective-C-style method with local and external parameter names.

Every function in Swift has a type, which consists of the function’s parameter types and return type. This means you can assign functions to variables or pass them as parameters to other functions:

func stringCharactersCount(s: String) - > Int { return s.characters.count } func stringToInt(s: String) - > Int { if let x = Int(s) { return x } return 0 } func executeSuccessor(f: String - > Int, s: String) - > Int { return f(s).successor() } let f1 = stringCharactersCount let f2 = stringToInt executeSuccessor(f1, s: "5555") // 5 executeSuccessor(f2, s: "5555") // 5556 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func stringCharactersCount ( s : String ) - > Int { return s . characters . count } func stringToInt ( s : String ) - > Int { if let x = Int ( s ) { return x } return 0 } func executeSuccessor ( f : String - > Int , s : String ) - > Int { return f ( s ) . successor ( ) } let f1 = stringCharactersCount let f2 = stringToInt executeSuccessor ( f1 , s : "5555" ) // 5 executeSuccessor ( f2 , s : "5555" ) // 5556

Swift also allows you to define default values for function parameters:

func myFunction(someInt: Int = 5) { // If no arguments are passed, the value of someInt is 5 } myFunction(6) // someInt is 6 myFunction() // someInt is 5 1 2 3 4 5 6 7 func myFunction ( someInt : Int = 5 ) { // If no arguments are passed, the value of someInt is 5 } myFunction ( 6 ) // someInt is 6 myFunction ( ) // someInt is 5

10. Do Statement

The do statement in Swift allows you to introduce a new scope:

let a = "Yes" do { let a = "No" print(a) // No } print(a) // Yes 1 2 3 4 5 6 7 8 9 10 let a = "Yes" do { let a = "No" print ( a ) // No } print ( a ) // Yes

Do statements can also contain one or more catch clauses:

do { try expression statements } catch pattern 1 { statements } catch pattern 2 where condition { statements } 1 2 3 4 5 6 7 8 9 10 do { try expression statements } catch pattern 1 { statements } catch pattern 2 where condition { statements }

For more info, please refer to the official Swift documentation for the do statement.

Conclusion

We firmly believe Swift is the future of iOS development, and with its open source nature and growing popularity, we can expect to see it used on other platforms in the future.

One of its most promising features is what Apple calls Protocol-Oriented Programming, a paradigm which may have a huge impact on software development in the future. In Swift, protocols (or “Interfaces” in languages such as C#) can be implemented by not only classes, but also enums and structs as well; furthermore, they provide an elegant and confusion-free alternative to multiple inheritance, as a single object can implement multiple protocols.

With its light, flexible syntax and numerous features to guard against common coding errors, Swift is simply a joy to program with. Give it a try yourself – you’re almost certain to agree. A good place to start is Apple’s official (and quite thorough) documentation for the language.

**//

About Redwerk

Being founded back in 2005, Redwerk had enough time to practice in developing iOS games, applications, e-government and local media solutions, etc.

Among the most challenging cases that helped us obtain and test out the experience in iOS development were the following:

School Observation App. A perfect solution for school supervisors. The development of this app was ordered by The Education Partners as they needed to record their notes on teachers, students and the school itself fast and easy, both on- and offline. Thanks to our previous experience, Redwerk was able to deliver a simple and user-friendly prototype in almost no time and quickly pass on to implementing the app. From the very beginning, performance was set as a key goal, for the app was supposed to handle massive amounts of media. It took us only three months to develop and launch a school observation app that will hopefully help The Education Partners maintain educational standards at the highest level.

Local Media Mobile Apps. Redwerk provided longlasting maintenance for a majority of Worldnow’s iOS local news apps. Our daily routine consisted of a number of problems, we needed to resolve regularly, such as news feed loading issues, duplicate content and weather report update fails. We also worked on adding new app blocks and features and modifying the existing ones according to current users needs.

YouTown. Our team was contracted to design and develop from the ground up a mobile application that would connect US citizens with their local authorities and provide an up-to-date city information anytime needed. Redwerk’s proud to say it took us only three months to deliver first fully functional betas of a web interface for government representatives and a mobile app for end users. Eventually, the app gained widespread currency in more than 20 cities inside and outside the United States and was finally acquired by a third-party company.

Aside from outsourced application development, we contribute a lot to in-house projects. Watching US presidential elections 2016 rule supreme, we decided to avail of this opportunity and improve our skills in developing multiplayer games with Unity. No sooner said than done, in just around 6 months time a team of two devs delivered Electoral.io, a dynamic cross-platform game available in both Android, iOS and browser versions.

Just like any other client of ours, be sure that a team of high-skilled devs and effective managers will do their best to deliver your project on time and at the highest possible level.

Don’t hesitate to outsource iOS development to Redwerk company for we have enough experience to satisfy every demand of yours.

Our developers are also experts in