In the
first part, we considered only a part of the new features of Swift 2:
- fundamental language constructs such as enums , scoping (scope), argument syntax, etc.
- pattern matching
- error handling
In the second part, we will look at the rest:
- protocol extensions
- availability check
- interaction with Objective-C and C
I will consider the new features of Swift 2, accompanying them with examples whose code is on
Github .
Protocol extensions
Protocol extensions were made possible in Swift 2, which made it possible to add new functions (complete with an implementation) to any classes, structures, and enumerations that implement the protocol.
')
Prior to Swift 2, both in Objective-C and Swift 1.x, the protocols contained only a declaration of methods. With protocol extensions in Swift 2, protocols can now include, along with the declaration, the implementation of methods. We have been waiting for this opportunity for Objective-C for years, so it's nice to see its implementation in a new language.
It often happens that some functionality needs to be added to all types that confirm a particular protocol (interface). For example, all collections can support the concept of creating a new collection based on the transformations of its elements. With old-style protocols, we could implement this possibility in two ways: 1) place the method in the protocol and require that each type confirming this protocol implement the method, or 2) write a global function that works on the values of the types confirming the protocol.
Cocoa (Objective-C) in most cases prefers the first solution.
Swift 1.x used the second solution. Global functions such as
map operated on any
CollectionType . This provided an excellent separation of code in the implementation, but terrible syntax and the inability to override the implementation for a specific type.
let x = filter(map(numbers) { $0 * 3 }) { $0 >= 0 }
With extensions of protocols, a third possibility has appeared, which significantly exceeds the other two.
The map can be implemented in the protocol extension
CollectionType . All types that support the
CollectionType protocol will automatically receive
map implementations for free.
let x = numbers.map { $0 * 3 }.filter { $0 >= 0 }
For example, consider in Swift 2 the implementation of the new
myMap method as an extension of the
CollectionType protocol.

As a result, we can immediately use
myMap for
Array <T> arrays

for dictionaries
Dictionary <Key: Value>
for sets
Set <T>
for
strings.characters
for ArraySlice
<T> slices
for StrideThrough
<T> straights, but not directly, but through a
map that converts a sequence (
SequenceType protocol) to a collection (
CollectionType protocol)

Protocol extensions underlie the new approach to software design, announced by Apple as a Protocol-Oriented Programming (EPP), existing in Swift along with traditional Object-Oriented Programming (OOP) and elements of Functional Programming (AF). It must overcome such OOP problems as “fragile base class” and the rigidity of inheritance (rigidity and fragility of inheritance),
“diamond problem” , implicit separation of references to objects, the need for frequent use of “casting” down (downcasting ) in overridden methods. It is also difficult for many developers to describe polymorphism with words, and it is easier to show with an example, we will demonstrate the capabilities of Protocol-Oriented Programming with examples.
Example 1. Fischer-Jens shuffle algorithm
For a deeper consideration of these differences, let us consider the implementation of
the Fisher – Jens Shuffle algorithm for “mixing” elements of a collection using the example of the
shuffle function for Swift 1.2 (OOP) and Swift 2 (POP). This algorithm is often used when dealing cards in a card game.
In Swift 1.2, we would add the global
shuffle function for working with collections according to method 2, that is, when using the global function with
generics :

Let's look at this feature in more detail. The input of this global function takes as its argument the collection
var list: C itself and returns a new collection of the same type
C with “mixed” values of the original
list collection. This global function can be used for all types that support the
MutableCollectionType protocol and have integer indices. There are two such collections:
Array <T> and
ArraySlice <T> slice

But look, what is the appeal to this global function?
shuffle(strings1) shuffle(numbers1)
This function does not allow using the “dot” notation; in the round brackets you need to specify the collection itself. This is very inconvenient if you have a whole chain of transformations, which leads to a lot of nested parentheses, and if this all alternates with the methods of the type, then in general - trouble. We have already seen a similar syntax above.
let x = filter(map(numbers) { $0 * 3 }) { $0 >= 0 }
If we want to work with the “dot” notation in Swift 1.2, then we add the
shuffle function to the extension of each individual type, for example, the
Array class (this is method 1). Moreover, we can add both the locally changing (mutating) method
shuffleInPlace and the shuffle method, which returns a new array with “mixed” elements of the original array (non — mutating)):

The last two methods are extensions for the
Array array and are available only for arrays.

Neither
Set nor
ArraySlice , no other
CollectionType can use them.
In Swift 2, we add the
shuffle and
shuffleInPlace methods exclusively to extend the
CollectionType and
MutableCollectionType protocols (method 3):

And with the extension of the protocols, the
shuffle and
shuffleInPlace methods can now be applied to
Set , and to
Array , and to
ArraySlice and any other
CollectionType without any additional effort, and in the “dotted” notation we need:

When extending protocols in Swift 2, we can set restrictions on the type. As you can see from the code, we first perform the protocol extension only for the
mutableCollectionType collection that is variable, which uses integers as indices, and then distribute it to the
CollectionType .
At the end, you need to make a small remark about the algorithm of "mixing" the elements of the collection. In Swift 2, there is already an efficient and correct implementation of the Fisher-Jens shuffle algorithm in
GameplayKit (which, despite its name, is not only suitable for games). True, this method works only with arrays.

Example 2. Farewell pipe (pipeline) operator |> with the advent of the possibility of extending protocols
With the advent of Swift and the creation of custom operators, including functional programming operators, attempts have been made and quite successful to solve some problems using functional programming techniques. In particular, for the Moon algorithm for calculating the check digit of a plastic card, it was proposed to use a pipe (pipeline) operator
|> to avoid annoying throwing between functions and methods. But Swift 2 came out and the protocol extension technique made it even easier to solve this problem.
The original algorithm described by the developer
- 1. Numbers of the checked sequence are numbered from right to left.
- 2. Figures that appear in odd places remain unchanged.
- 3. Numbers in even places are multiplied by 2.
- 4. If as a result of such multiplication a number greater than 9 appears (for example, 8 × 2 = 16), it is replaced by the sum of digits of the resulting work (for example, 16: 1 + 6 = 7, 18: 1 + 8 = 9) - by a single-digit number that is, a number.
- 5. All the resulting conversion figures are added. If the sum is a multiple of 10, then the source data is correct.
The algorithm consists of a sequence of steps, each of which will be described using an extension of either a protocol, or a type, or using known methods.
First, you need to be reminded that in Swift 2 the
String is no longer a sequence, but
String.characters is a sequence of characters, and we need to convert a character to an integer. We construct this transformation on an extension of type
Int . That is, instead of
String.toInteger we get
Int.init (String) :

This conversion returns an Optional, since there may be spaces in the credit card number, and we need to continue to perform arithmetic operations on the obtained integers, so we use the
flatMap method that appeared in Swift 2, which will remove all spaces in the card number

According to our algorithm, we have to consider numbers from right to left, and here they follow from left to right, therefore we will arrange our sequence of numbers in the opposite direction using the
reverse method and the trivial
map method

But we need not a simple
map , but a
map that performs transformations only on each Nth member of the sequence. Again we execute the extension, but now not of the type, but of the protocol
SequenceType
We get the following result

Then we need a method to calculate the sum of any sequence containing integers:

and method of calculating the number modulo another number

As a result, we get the
luhnchecksum () method, which we add to the
String type and which calculates the checksum in one string

Now it's very easy to get the result:

Some features of the protocol extension
I think that protocol extensions can be Apple’s answer to the question of optional protocol methods. Pure Swift protocols cannot and should not have optional (optional) methods. But we are used to the optional (optional) methods in Objective-C protocols, for example, for such things as delegates:
@protocol MyClassDelegate @optional - (BOOL)shouldDoThingOne; - (BOOL)shouldDoThingTwo @end
Pure Swift has no equivalent:

Until now, everyone who confirmed this protocol had to implement all these methods. This conflicts with the idea of delegating Cocoa as an option to optionally configure all delegate methods, preferring the default implementation of the methods. With the advent of protocol extensions in Swift 2, reasonable default behavior can be provided by the protocol itself:

Ultimately, this provides the same functionality as Objective-C’s
@optional , but without mandatory checks at runtime.
API availability check
One professional problem that depresses iOS developers is the need to be very careful when using new
APIs . For example, if you try to use
UIStackView in iOS 8, then your application will crash. In ancient times, Objective-C developers would write similar code:
NSClassFromString(@"UIAlertController") != nil
This means “if the
UIAlertControllerl class exists,” and is a way to check whether it runs on iOS 8 or later. But due to the fact that Xcode did not guess the true purpose of this code, it did not guarantee us the correctness of its execution. Everything changed in Swift 2, because you can write such code explicitly:
if #available(iOS 9, *) { let stackView = UIStackView()
The magic happens with the appearance of the
#available clause : it automatically checks whether you are running on iOS version 9 or later, and if “yes”, then the code from
UIStackView will be launched. The presence of a “*” after “iOS 9” means that this offer will be executed for any future platform that Apple will introduce.
The
#available clause is
also remarkable because it gives you the opportunity to write code in the
else block, because Xcode now knows that this block will be executed if iOS 8 or less is on the device and can warn you if you will use new APIs here . For example, if you wrote something like this:
if #available(iOS 9, *) { // do cool iOS 9 stuff } else { let stackView = UIStackView() }
... then you get an error:

Xcode sees that you are trying to use
UIStackView where it is not available and it simply will not allow this to happen. So, switching from “whether this class is“ available ”to telling Xcode about our real intentions, we received tremendous support for our security.
Compatibility
When you write code in Swift, that is, a number of pre-
written rules that tell the compiler whether you need and how, expose methods, properties, etc. on Objective-C. Moreover, at your disposal there are a small number of attributes with the help of which you can control this process. These attributes are:
- @IBOutlet and @IBAction allow Swift properties and methods to be interpreted as outlets and Actions in Interface Builder;
- dynamic , which allows you to use KVO for a given property;
- @objc , which is used to make a class or property called from Objective-C.

In Swift 2, a new such attribute
@nonobjc has appeared , which clearly prevents the use of properties or methods from being exposed in Objective-C. This attribute is very useful, for example, in the following case. In the Calculator application (see below), in the
ViewController class, which inherits from the
UIViewController Cocoa class, you define 3 methods with the same name
performOperation , but with different arguments. This is normal, Swift is able to distinguish between these methods, simply based on the different types of argument. But Objective-C doesn't work that way. In Objective-C, methods differ only by name, not by type. If these methods are exposed for use in Objective-C, then you will get an error saying that you cannot use them in this form in Objecrive-C. The thing is that our
ViewController class, which we created for the calculator interface, inherits the
UIViewCiontroller class from Cocoa, and the compiler automatically implicitly marks all properties and methods with the
@objc attribute. If you do not intend to use methods in Objective-C, then you must supply them with the
@noobjc attribute and the error disappears:

.........................

Another area in which Swift 2 is trying to improve compatibility is compatibility with C function pointers. The purpose of this improvement is to fix the Swift annoying constraint, which does not allow you to fully work with such an important C - framework as
Core Audio , which intensively uses callback functions. In Swift 1.x, it was not possible to directly replace the pointer with the Swift function with a function. You needed to write a small “wrapper” in C or Objective-C that encapsulates the callback function. In Swift 2, it became possible to do this in a completely natural way for Swift 2. Pointers to C functions are imported into Swift as closures. You can pass any Swift 2 closure or function with suitable parameters to a code that expects a pointer to a C function — with one significant limitation: in contrast to closures, pointers to C functions do not have the concept of a “captured” state (they are just pointers). As a result, for compatibility with pointers to C functions, the compiler will allow using only those Swift 2 closures that do not “capture” any external context. Swift 2 uses the new
@ convention © notation to indicate this agreement when calling:

For example, for the standard C sorting function
qsort, it would look like this:

A very good example is presented in
C Callbacks in Swift , which shows how to access
CGPath or
UIBezierPath elements by calling the
CGPathApply function and passing a pointer to the callback function.
CGPathApply then calls this callback for each path element.


Now go through the entire
path and print a description of its elements:

Or you can count how many
closepath commands in this
path are :

In conclusion, we can say that Swift 2 automatically provides compatibility (bridges) of pointers to C functions and closures. This makes it possible (and very convenient) to work with a large number of C APIs that use function pointers as callbacks. Because conventions on calls to C functions do not allow these closures to “capture” an external state, you often have to pass external variables that your callback needs to access, via a
void pointer, which many C APIs
New Objective-C Features
Apple introduced three new features in Objective-C in Xcode 7 with an eye to using them for smoother Swift compatibility:
- nullability;
- lightweight generics;
- __kindof types.
Nullability
This feature was introduced already in Xcode 6.3, but it is worth mentioning that Objective-C now allows you to accurately characterize the behavior of any methods and properties to determine whether they can be
nil or not. This is addressed directly to Swift's requirements for
Optional or non-
Optional types and makes the Objective-C interface more expressive. There are three qualifiers for
nullability :
- nullable ( __nullable for C pointers), meaning that the pointer can be nil and is converted to Swift as an Optional type - ? ;
- nonnull ( __nonnull for C pointers), meaning that nil is not allowed and is converted to Swift as a non- Optional type;
- null_unspecified ( __null_unspecified for C pointers), no information on what behavior is supported; in this case, such a pointer is converted to Swift as an automatically “expanded” Optional - ! .
The qualifiers listed above can be used to annotate Objective-C classes, as in the following example:

In this example, the whole area marked with the brackets
NS_ASSUME_NONNULL_BEGIN and NS_ASSUME_NONNULL_END is selected so that
nonnull has a value that is used by default. This allows the developer to annotate only those elements that do not correspond to the default value.
Lightweight generics
Lightweight
generics in Objective-C may be the most desirable in Objective-C over the past decade, especially for Apple engineers. They are necessary for use with collections like
NSArray ,
NSDictionary , etc ... One of the disadvantages of collections in Objective-C is the loss of almost all type information when porting them to Swift, by default in Swift we get the
AnyObject collection and have to apply down "casting "In the overwhelming number of cases. But now you can declare the type of array elements in Xcode 7 as follows:

In our case, we declare a variable array of strings. If you try to write a number into it, the compiler will issue a warning about the type mismatch.
Lightweight
generics have proven very useful for interoperability between Objective-C and Swift in terms of representing the
NSArray ,
NSDictionary , etc. classes, because now you don’t need to do a lot of "castings" in your Swift code because all Apple frameworks are written in Objective-C.

Do you see? Now the
subviews are not an
[AnyObject] array, they are passed to Swift as
[UIView] .
Now in Objective-C you can declare your own
generic class:

And use it

In case of a type mismatch, a warning is issued. Unfortunately, using your own
generic types takes precedence only within Objective-C code and is ignored by Swift. They operate only at the compiler level, they are not in runtime.
__kindof types
__kindof types belong to
generics , and their appearance is motivated by the following case. As is known, the
UIView class has a
subviews property, which is an array of
UIView objects:
@interface UIView @property(nonatomic,readonly,copy) NSArray< UIView *> *subviews; @end
If you add
UIButton to the parent
UIView as the most remote
subview in the background, and try to send him a message that matters only for
UIButton , the compiler will issue a warning. This is good, but we know for sure that the
subview in the background is a
UIButton and we want to send a message to it:
[view insertSubview:button atIndex:0]; //-- warning: UIView may not respond to setTitle:forState: [view.subviews[0] setTitle:@"Cancel" forState:UIControlStateNormal];
Using the
__kindof type, we can provide some flexibility to the typing system in Objective-C so that the implicit "casting" of both the superclass and any subclass works:
@interface UIView @property(nonatomic,readonly,copy) NSArray< _kindof UIView *> *subviews; @end
The lightweight
generics and
__kindof types allow the developer to remove
id / AnyObject almost everywhere from most of their APIs.
The id may still be required in cases where there really is no information on what type you are dealing with:
@property (nullable, copy) NSDictionary<NSString *, id> *userInfo;
Links to articles used
New features in Swift 2What I Like in Swift 2A Beginner's guide to Swift 2Error Handling in Swift 2.0Swift 2.0: Let's try?Video Tutorial: What's New in Swift 2 Part 4: Pattern MatchingThrow What Don't ThrowThe Best of What's New in SwiftWhat's new in Swift 2Swift 2.0: Availability Checking APIHow do I shuffle an array in Swift?Swift 2.0 shuffle / shuffleInPlaceC Callbacks in Swift,Protocol extensions and the death of the pipe-forward operatorSwift protocol extension method dispatchAPI Availability Checking in Swift 2Interacting with C APIsWhat's new in iOS 9: Swift and Objective-CXcode 7 Release Notes