23 Different Capabilities of Swift from Objective-C

23 Different Capabilities of Swift from Objective-C


In this article, I’ll talk about the difference in the capabilities that the iOS developers give to the languages Swift and Objective-C. Of course, the developers who were interested in the new language from Apple have already seen a lot of similar articles, so I decided to focus on the differences that affect the development process and the architecture of the application. That is those differences that you need to know to use the language as efficiently as possible. I tried to compile a complete list that meets these criteria.

Also, when I talked about new features Swift brought to the development, I tried to remember to mention what he lost in comparison with Objective-C.

For each item, I tried to briefly outline the essence of the difference, without going into details, and sample code – on the contrary, to make detailed. In them, I commented on all the nuances, even those that are not directly related to the difference in question.

At the time of this writing, the current version of Swift is 3.0.1.

1. Classes, structures, and transfers

The classes in Swift do not have the same common ancestor, like NSObject in Objective-C. Moreover, classes may not have an ancestor at all.

The structures in Swift are almost as functional as classes. They, like classes, can have static and standard properties and methods, initializers, subscripts, extensions, and can implement protocols. From classes, they differ in that they are passed by value and do not have inheritance.

// An example of a structure that demonstrates its capabilities.
// The class is defined in the same way.
// That is if in the example, replace the word struct with class,
All the code remains correct.
Struct Rocket {
// A property of the type of an array of elements of type Stage.
// Variable is defined by keyword var, let word is constant.
Var stages: [Stage]

// Static property of type Int.
//  The type is determined by the compiler from the initialization.
Static let maxAllowedStages = 4

// A method that does not accept arguments and does not return a value.
// This is a shortcut for launch () -> Void or launch () -> ().
// Where Void is actually typealias for ()
// A () stands for an empty tuple.
//  So, in fact, this method returns an empty tuple.
Func launch () {
// ...
}

// Static type method ([Stage]) -> Double.
Static func calculateHeight (for stages: [Stage]) -> Double {
// The reduce method is defined for collections in Swift.
// It converts the collection into one value.
// For this, it takes an initial value and closure,
// Which is called for each item in the collection.
// It must, based on the already accumulated meaning.
// The element of the array, calculate the new value of the battery.
Return stages.reduce (0) {(accumulator, stage) -> Double in
Return accumulator + stage.height
}
}

// Failable initializer.
// That is one that can return nil instead of an instance.
// Standard initializers are declared without question mark after the word init.
Init? (Stages: [Stage]) {
If stages.count> Rocket.maxAllowedStages {
Return nil
}
Self.stages = stages
}

// The subscript allows you to access the object using square brackets
//  As an array or a dictionary.
// Rocket [1] = stage.
// Here we just delegate the index to the internal array,
// But you can write your own logic.
// One type can define multiple indexes.
//  But they must take different types.
Subscript (index: Int) -> Stage {
Get {
Return stages [index]
}
Set (newValue) {
Stages [index] = newValue
}
}
}

// We will announce a protocol defining the requirements for the object for transportation by train: The opportunity to be dismantled by wagons and collected back.
Protocol TransportableByTrain {
Func placeOnTrain () -> [Carriage]
Init (train: [Carriage])
}

// Extensions allow you to add to existing classes, structures, and enums
Properties, methods, initializers, indexes, nested types, and protocol implementation.
Extension Rocket: TransportableByTrain {
Func placeOnTrain () -> [Carriage] {
Return stages.map {stage in
Return Carriage (content: stage)
}
}

Init (train: [Carriage]) {
Let stages = train.map {
$ 0.content as! Stage
}
Self.init (stages: stages)!
}
}

Enumerations in Swift may not have values.

// Enumeration without rawValue.
Enum LaunchState {
Case preparing, ready, launching, failed, succeeded
}

But, if there are values, then they can be not only integers, but also real numbers, and strings, and symbols. Enumeration instances are not automatically coded to internal value types, so you must use the rawValue property to access them.

</pre>
// Enumerate with rawValue.
Enum LaunchEvent: Int {
Case poweredOn = 1, fuelLoaded, oxidizerLoaded, countAutoSequenceStarted,
GoForlaunchVerification, preLaunchChecks, pressurizePropellantTanks,
IgnitionSequenceStart, liftoff
}
Let lastEvent = LaunchEvent.liftoff
LastEvent.rawValue // 9
// Enumerations from `rawValue` automatically receive a failable initializer
From the corresponding type.
Let firstEvent = LaunchEvent (rawValue: 1) //LaunchSequence.poweredOn
Let nonexistentEvent = LaunchEvent (rawValue: 0) // nil
<pre>

If the enumeration does not have a rawValue, then each count case can have its associated values. There can be several, and they can be of any type.

</pre>
// Enumeration with associated values.
Enum LaunchError {
Case compromisedHullIntegrity (stage: Stage)
Case engineMalfunction (engine: Engine, malfunction: Malfunction)
Case unrecognizedError
}
<pre>

Enumerations, as well as structures, are passed by value. And they have the same features listed above, except the stored properties. Properties for enumerations can only be computed properties.

</pre>
// The static calculated property of the count.
Extension LaunchEvent {
Static var sequence: [LaunchEvent] {
Return Array (1 ... 9) .map {LaunchEvent (rawValue: $ 0)! }
}
}
<pre>

This rich functionality of structures and enumerations allows us to use them instead of classes where values are more appropriate than objects. The purpose of this separation is to simplify the application architecture. More about managing complexity:

2. Types of functions, methods, and closures

In Swift, functions, methods, and closures are first class citizens, that is, they have types and can be stored in variables and passed as a parameter to a function. The types of functions, methods, and closures are determined only by the returned and received values. That is, if a variable of a particular type is declared, then it can store both a function, a method, or closure. Instances of these types are passed by reference.

This unification of entities has led to a simplification of their use. In Objective-C, the transfer of the object and the selector or the transmission of the block solved, in principle, the same problem. In Swift, such an API will require something with certain accepted and returned values, and what exactly will be passed there: a function, a method, or closure; irrelevant.

</pre>
// The reduce method that we used in calculateHeight has the following type.
// (Result, (Result, Element) throws -> Result) rethrows -> Result.
// But in this example, we omit the details related to error handling: throw and Rethrows; And the generic type Result and the associated type Element are replaced by Specific Double and Stage types.
// With these assumptions, we can say that the reduce method has the following form.
// (Double, (Double, Stage) -> Double) -> Double.
// The method takes two parameters: the first type is Double, and the second is the closure.
// Receiving Double and Stage, and returning Double. And the method itself, in its Queue, too, returns Double.

// The most complete call record of this method with a closure looks like this:
Let totalHeight = stages.reduce (0, {(accumulator: Double, stage: Stage) -> Double in
Return accumulator + stage.height
})

// But usually a shorter record is used.
// First, from the type of the reduce method, the compiler already knows the returned and received.
// Values of the parameter-closure, so that they can be omitted.
// Secondly, if the closure is the last parameter in the list, then it can be carried out For the brackets.

Let totalHeight = stages.reduce (0) {accumulator, stage in
Return accumulator + stage.height
}

// Such a record is the most common.
// But the possibilities of reduction are not limited on this.
// You can not specify your names for the parameters of the closure. In this case.
// They can be accessed through $ 0, $ 1, and so on in order.
// If the closure contains only one expression, you can omit the key.
// The word return.
Let totalHeight = stages.reduce (0) {$ 0 + $ 1.height}

// Moreover, operators in Swift also have the same types of functions,
// Methods and closures.
// In our example, the + operator is not defined for Double and Stage types, but if.
// We from an array of steps [Stage] would receive an array of heights [Double], and already at it.
// Called reduce, then the second parameter would be of type (Double, Double) -> Double.
// And for Double, the + operator is defined, so instead of closing, we could simply.
// Transfer it.
Let totalHeight = stages.map {$ 0.height} .reduce (0, +)
<pre>

3. Default settings

Parameters of functions and methods can have default values.
Using default settings instead of several functions/methods reduces the amount of code, and less code – fewer bugs.

</pre>
Enum Destination {
Case lowEarthOrbit, geostationaryEarthOrbit, transLunarInjection
}

Class RocketFactory {
// Default values are specified in the declaration after the parameter type through the '=' sign.
Func makeRocket (destination: Destination = Destination.lowEarthOrbit,
PayloadMass: Double = 6450) -> Rocket {
// ...
}
}

Let rocketFactory = RocketFactory ()
// Parameters with default values can be omitted when called.
Let soyuz = rocketFactory.makeRocket ()
Let protonM = rocketFactory.makeRocket (destination: Destination.geostationaryEarthOrbit)
Let saturnV = rocketFactory.makeRocket (destination: Destination.transLunarInjection, payloadMass: 48600)
<pre>

4. Options

Variables of any type can not take the values nil. In Swift, a particular type of Optional is used, into which other types “wrapped up” if there is a need to represent the absence of value.

Optional – these are enumerations with two cases: none and some. Optional.some (Wrapped) contains the value of the wrapped type as an associated value.
Optional.none is equivalent to the literal nil.
In Optional, it can wrap both the reference type and the value-passing one.

</pre>
Struct Launchpad {
// Convenient entry for optional type.
Var rocket: Rocket?
// Without syntactic sugar this would look like this: Var rocket: Optional <Rocket>.
}
<pre>

To access the properties and methods of arbitrary values, you first need to expand these absolute values, that is, make sure that they are not nil. Of course, this can be achieved by working with arbitrary values as with regular enumerations, for example using a switch, but in Swift, there are more useful constructs for this: if let, the guard let else; Operators:?!, ??.

</pre>
// The simplest, but unsafe way to deploy an optional variable is.
// Operator '!'. It returns an optional type if successful, but calls runtime error and.
// Drop application if inside nil.
Launchpad.rocket! .launch ()

Func start () {
// The typical way to implement optional values is to use Constructs if let.
If let rocket = launchpad.rocket {
// Thus, inside the successful branch, we get a new variable
// Not optional type.
Rocket.launch ()
} Else {
// And in the else branch, we can handle the absence of value in an optional variable.
AbortStart ()
}
}

// In situations where continuing execution does not make sense, if optional.
// The value is nil, to deploy optional values it is convenient to use.
// Guard let construct.
Func start2 () {
// Unlike if let, it declares a new variable with a non-optional type in the current.
// Context, and inside the else block, handle the hit on nil and exit Context.
Guard let rocket = launchpad.rocket else {
AbortStart ()
Return
}
Rocket.launch ()
}

// There is a way to access the properties and methods of optional values without expanding him. This is the '?' Operator. With such a call, we do not receive any feedback about Presence or absence of meaning.
// The return value of this call will always be optional.
Launchpad.rocket? .launch ()

Var possibleLaunchpad: Launchpad

// In this way, several optional values can be associated.
PossibleLaunchpad? .rocket? .launch ()
PossibleLaunchpad? .rocket? .stages // Return type: [Stages]?

// Another operator with arbitrary values is the Operator '??'. It has two operands.
// The first is optional, and the second is not optional of the same type.
// If the first operand is not nil, the value is expanded and returned, otherwise.
// The second operand is returned.
Let certainRocket = possibleLaunchpad? .rocket ?? RocketFactory.makeRocket ()
<pre>

Such restrictions make it difficult for an unexpected hit on the nil value, which makes Swift code more reliable.

5. Nested types

In Swift, you can declare nested types, that is, classes, structures, and enumerations can be reported within each other.

</pre>
// If we wanted to separate the launch into a separate entity, we could
// Get something like that.
Struct Launch {
Enum State {
Case preparing, ready, launching, failed, succeeded
}
// Within a context, you can access a nested type simply by name.
Var state: State = .preparing
}
// Outside of the nested type, if it is available, you can access it via the name
// External type.
Let launchState: Launch.State
<pre>

6. Tuples

Even new types in Swift are tuples. Tuples allow you to combine several values of any types into one compound value. Tuples are passed by value.

</pre>
// By specifying the type of the tuple, the values can be given names so that in the future.
// Contact them, not by the number.
Var launchEventMark: (event: LaunchEvent, timeMark: Int) = (.ignitionSequenceStart, 6600)
LaunchEventMark.event
LaunchEventMark.timeMark
// However, the reference to the number in this case does not disappear.
LaunchEventMark.0
LaunchEventMark.1
// It should be noted that if we declare a tuple with values of the same types, but without.
// Titles, we get a tuple of the same type, and we can assign the previous one.
// The value of the new variable.
Var anotherMark: (LaunchEvent, Int) = launchEventMark
AnotherMark.0
AnotherMark.event // error: type has no member 'event'
<pre>

7. Getters, setters and property observers

Unlike Objective-C, in Swift, getter, and setter can only be defined for computed properties. Of course, for stored resources like getter and setter, you can use methods or a calculated property.

</pre>
// Implement getter and setter using the calculated property.
Class ThrustController {
Init (minThrust: Double, maxThrust: Double, currentThrust: Double) {
Self.minThrust = minThrust
Self.maxThrust = maxThrust
Thrust = currentThrust
}

Var minThrust: Double
Var maxThrust: Double

Private var _thrust = 0.0

Var thrust: Double {
Get {
Return _thrust
}
Set {
If newValue> maxThrust {
_thrust = maxThrust
} Else if newValue <minThrust {//
_thrust = maxThrust
} Else {
_thrust = newValue
}
}
// By default, the setter value from setter is available by name NewValue, but you can give it your name:
// set (thrustInput) {...}
}
}
// But, generally, the computed properties are usually used in situations where Value can be calculated based on other properties, not for Validation of values.
<pre>

For tasks whose solution requires tracking the change in the value of property, a new mechanism has emerged – the property observers. They can be defined for any stored property. They are of two types: willSet (called before changing the value of the ownership) and didSet (called immediately after setting a new value).

</pre>
Protocol ThrustObserver: class {
Func thrustWillChange (from oldValue: Double, to newValue: Double)
Func thrustDidChange (from oldValue: Double, to newValue: Double)
}

Class ThrustMeter {
Weak var observer: ThrustObserver?

Var thrust: Double = 0.0 {
WillSet {
Observer? .thrustWillChange (from: thrust, to: newValue)
}
DidSet {
Observer? .thrustDidChange (from: oldValue, to: thrust)
}
// As with set, the names newValue and oldValue can be replaced with their own.
// willSet (newThrust) {...}
// didSet (oldThrust) {...}
}
}
<pre>

For lazy initialization, which in Objective-C can be implemented via a getter, Swift has a lazy property modifier.

8. Variability of properties and collections

In Swift, type properties can be constants. Moreover, if the kind of a property declared as a constant is a class, that is, a type that is passed by reference, then only the reference itself will be immutable. That is, you can not assign a new object to this property, and you can modify the properties of this object. For types passed by value, any change will be unacceptable.

</pre>
Class ThrustMeterClass {
Var thrust: Double

Init (thrust: Double) {
Self.thrust = thrust
}
}

Struct ThrustMeterStruct {
Var thrust = 0.0
}

Let thrustMeterClass = ThrustMeterClass (thrust: 0)
ThrustMeterClass = ThrustMeterClass (thrust: 50) // Error
ThrustMeterClass.thrust = 50 // OK

Let thrustMeterStruct = ThrustMeterStruct (thrust: 0)
ThrustMeterStruct = ThrustMeterStruct (thrust: 50) // Error
ThrustMeterStruct.thrust = 50 // Error
<pre>

Since in Swift all collections are structures, their variability is determined not by the type, as in Objective-C, but by the declaration method – a constant or a variable. Collections in the standard library are three: an array, a set, and a dictionary.

</pre>
Let immutableArray = [1, 2, 3]
Var mutableArray = [1, 2, 3]
<pre>

9. Protocols with associated types

While the common rules are almost identical to the analogs from Objective-C, contracts with associated types are a whole new design in Swift. Protocols can declare associated types and use them as placeholders in their requirements for methods and properties. And what implements this protocol, should already specify what real type will be utilized.

</pre>
// Declare some empty regular protocols for the following examples.
Protocol Fuel {}
Protocol Oxidizer {}

// Declare several types that implement these protocols.
Struct Hydrazine: Fuel {}
Struct ChlorineTrifluoride: Oxidizer {}
Struct Kerosene: Fuel {}
Struct Oxygen: Oxidizer {}

// Protocol with associated values.
Protocol Bipropellant {
// You can impose requirements on associated types Protocols or class inheritance.
Associatedtype TFuel: Fuel
Associatedtype TOxidizer: Oxidizer

Func burn (_ fuel: TFuel, with oxidizer: TOxidizer)
}

// Declare the class with the implementation of such a protocol.
Struct KoxPropellant: Bipropellant {
// Tell the compiler which particular type will be used in this Protocol implementation, you can use type alias. But in this case, it is not.
// It is mandatory since it can derive it from the signature of the burn method.
Type alias TOxidizer = Oxygen
Type alias TFuel = Kerosene

Func burn (_ Fuel: Kerosene, with oxidizer: Oxygen) {
Print ("Burn of kerosene with oxygen.")
}
}

// Protocols can also be inherited from other protocols, as it was in Objective-C.
Protocol Hypergolic: Bipropellant {}

Struct HctPropellant: Bipropellant, Hypergolic {
Typealias TOxidizer = ChlorineTrifluoride
Typealias TFuel = Hydrazine

Func burn (_ fuel: Hydrazine, with oxidizer: ChlorineTrifluoride) {
Print ("Burn of hydrazine with chlorine trifluoride.")
}
}
<pre>

While conventional protocols can be used as a particular type:

</pre>
Struct AnyFuelTank {
// You can store a value of any type that implements this variable the Fuel protocol.
Var content: Fuel
}

Var fuelTank = AnyFuelTank (content: kerosene)
FuelTank.content = hydrazine
<pre>

Protocols with associated types can not be used like this.

</pre>
Struct RocketEngine {
// Such a record does not compile.
Var propellant: Bipropellant
// Error: Protocol 'Bipropellant' can only be used as a generic constraint Because it has Self or associated type requirements.
}
<pre>

As you can see from the error message, protocols with associated values can only be used as a constraint on the generic type.

Struct RocketEngine <TBipropellant: Bipropellant> {
    Var propellant: TBipropellant
}

With some reflections on the topic, why this is so and how to live with it, is available here: 3.

In general, the protocols with associated values are well described in this series of articles: 4.

10. Contract extensions

Extensions of classes, structures, and enumerations in Swift are fundamentally similar to categories and extensions from Objective-C, that is, they allow you to add behavior to a type even if you do not have access to its source code. Type extensions enable you to add computed properties, methods, initializers, subscripts, nested types, and implement protocols.

Contract extensions are a new feature in Swift. They allow you to provide the types implementing this protocol with the implementation of properties and methods by default. That is, the extension of the protocol describes not requirements, but a particular implementation that will be received by the types implementing this protocol. Of course, classes can override this implementation. This application by default allows you to replace the optional protocol requirements, which in Swift exist only within the framework of compatibility with Objective-C.

</pre>
// All types implementing this protocol will get this method implementation.
Extension Bipropellant {
Func burn (_ fuel: TFuel, with oxidizer: TOxidizer) {
Print ("Common burn.")
}
}
<pre>

Also, in the protocol extension, you can implement methods that are not in the contract requirements, and these methods will also be applied to the protocol types. But using contract extensions in this way should be done with caution because of static binding.

Moreover, you can specify the protocol extensions so that not all types implementing the protocol get the default implementation. Conditions can require that a type is inherited from a particular class or apply certain rules. Conditions can be superimposed on the type itself, which implements the protocol and on the associated types. If different extensions provide the implementation of the same method, and the type satisfies the conditions of several extensions, then it will get the implementation whose expansion situation was more particular. If this is not the case, then the type will not get any implementation.

</pre>
// Since this extension is more accurate than the previous one, the types.
// Those who satisfy the requirement will receive this implementation of the method.
Extension Bipropellant where Self.TOxidizer == Oxygen {
Func burn (_ fuel: TFuel, with oxidizer: TOxidizer) {
Print ("Burn with oxygen as oxidizer.")
}
}

// You can impose several requirements separated by a comma. Requirements
// Are combined by a logical AND.
Extension Bipropellant where Self: Hypergolic, Self.TFuel == Hydrazine {
Func burn (_ fuel: TFuel, with oxidizer: TOxidizer) {
Print ("Self-ignited burn of hydrazine.")
}
}

// Since the previously mentioned types KoxPropellant and HctPropellant define their own Implementation of the burn method, they do not receive implementation from extensions Protocol Bipropellant.
Let koxPropellant = KoxPropellant ()
KoxPropellant.burn (kerosene, with: oxygen) // Burn of kerosene with oxygen.

Let hctPropelant = HctPropellant ()
HctPropelant.burn (hydrazine, with: chlorineTrifluoride) // Burn of hydrazine with chlorine trifluoride.

// But if they do not explain the burn method for them, they would get the following implementations.
KoxPropellant.burn (kerosene, with: oxygen) // Burn with oxygen as oxidizer.
HctPropelant.burn (hydrazine, with: chlorineTrifluoride) // Self-ignited burn of hydrazine.
<pre>

In general, the extension of the protocols can be seen in WWDC15 “Protocol-Oriented Programming in Swift” by Dave Abrahams [6]

11. Generics

Unlike Objective-C, Swift generic can have not only classes but also structures, enumerations, and functions.

In Swift, the conditions on the generic type can be superimposed in the same manner as in Objective-C, that is, to inherit from a particular class or implement certain protocols. Also, if there is a requirement to apply a protocol with associated types in the environment, then you can impose similar conditions on them.

</pre>
// No restrictions Tank can be specialized for any type.
Struct Tank <TContent> {
Var content: TContent
}

// Limit the implementation of the protocol.
Struct FuelTank <TFuel: Fuel> {
Var content: TFuel
}

// Limit the implementation of the protocol and the associated type.
Struct OxygenEngine <TBipropellant: Bipropellant> where TBipropellant.TOxidizer == Oxygen {
Var fuel: TBipropellant.TFuel
Var oxidizer: Oxygen
}
<pre>

12. The namespace

In Objective-C, to avoid name conflicts, you need to use prefixes in the names of classes and protocols.

In Swift, each module has its namespace, and in the case of the intersection of type names to the desired one can be accessed through the name of its module. The ability to declare your namespace to separate the types within one module is not yet available.

13. Access Control

In Objective-C, access control is performed by spreading the interface along two files. The public properties and methods interfaces are specified in the header file, and the private interfaces are in the implementation file.

In Swift, there is no division of the type declaration into two files, and access control is performed using special modifiers.

Swift 3:

Open – access from this module and from the modules that import this module.
Public – full access from this module, and from modules that import this module without the possibility of class inheritance and method overriding.
Internal – access only from this module.
Five private – access only from this file.
Private – Access only from this ad or extension.

14. Error Handling

Objective-C uses two mechanisms for error handling: NSException and NSError. The exception mechanism with NSException is throwing and catching errors with @try, @catch, @finally; And the mechanism with NSError is passing the pointer to NSError * and then processing the set value. And in Cocoa, you rarely have to catch NSException, because NSException is usually used for unrecoverable errors, and for errors that require processing, NSError is used.

In Swift, there is a fundamental error-handling mechanism called do-try-catch, which replaced NSError. It should be noted that there is no finally block in this mechanism. Instead, you should use the defer block, whose code is executed when you exit the scope, and it, in principle, is not related to error handling and can be used anywhere.

As for NSException, then, because of compatibility with Objective-C, they work, but you can not catch them in Swift.

</pre>
Protocol Technology {}

// You can use any type as an error, just implement it Protocol Error. It does not contain any requirements but allows you to use Type in the throw and catch constructs. * /
// Usually, the enumeration is used for errors.
Enum ConstructingError: Error {
Case notEnoughFunding (shortage: Double)
Case neccessaryTehcnologyIsNotAvailable (technology: Technology)
Case impossibleWithModernTechnology
}

Class ThrowingRocketFactory {
Var funds: Double = 0.0
Func estimateCosts () -> Double {
Return 0.0
}

// A method that can throw errors must be indicated by a key.
// The word throws after the arguments.
Func makeRocket (for destination: Destination, withPayloadMass payloadMass: Double) throws -> Rocket {
// ...
If funds <= 0 {
Throw ConstructingError.notEnoughFunding (shortage: estimateCosts ())
}
// ...
}
// ...
}

Let factory = ThrowingRocketFactory ()
Let destination = Destination.lowEarthOrbit
Let payloadMass = 0.0

// You can call throwing methods only with the try keyword.
// There are several things that you can do with throwing methods and their errors.

// 1) The error can be thrown further. For this, the method in which the The throwing method is also marked as throws.
Func getRocket (forDestination destination: Destination, payloadMass: Double) throws -> Rocket {
Let rocketFactory = ThrowingRocketFactory ().
Let rocket = try rocketFactory.makeRocket (for: destination, withPayloadMass: payloadMass)
Return rocket
}

// 2) An error can be caught. To do this, the calling method must be called In the do block, and subsequent catch blocks should catch all possible errors.
Do {
Let rocket = try factory.makeRocket (for: destination, withPayloadMass: payloadMass)
} Catch ConstructingError.notEnoughFunding (let shortage) {
Print ("Find money: \ (shortage)")
} Catch ConstructingError.neccessaryTehcnologyIsNotAvailable (let technology) {
Print ("Find alternatives for: \ (technology)")
} Catch {
Print ("Impossible to create such rocket.")
}

// 3) The result of the throwing method can be turned into optional, giving up Information about the error.
If let rocket = try? Factory.makeRocket (for: destination, withPayloadMass: payloadMass) {
// ...
}

// 4) You can ignore the possibility of error. But if it does, This will cause the application to crash in runtime.
Let rocket = try! Factory.makeRocket (for: destination, withPayloadMass: payloadMass)

// To demonstrate the defer block, suppose that you must first order missiles To open communication with the plant, and then necessarily close at any outcome.
Extension ThrowingRocketFactory {
Func openCommunications () {/ * ... * /}
Func closeCommunications () {/ * ... * /}
}

Do {
Factory.openCommunications ()
Defer {
// The code inside the defer block will be called when the current scope is left, In this example, the do block. And it does not matter whether it will happen because of.
// Or an error in the normal execution of commands.
Factory.closeCommunications ()
}
Let rocket = try factory.makeRocket (for: destination, withPayloadMass: payloadMass)
} Catch {
// ...
}
<pre>

15. Memory management

In Swift, as in Objective-C, reference counting is used, but automatic counting of links can not be disabled. And when working with a low-level procedural API, all objects returned are wrapped in the Unmanaged structure. The reference counter of such an object can be managed manually through the construction methods: retain (), release (), autorelease (); But to gain access to such an object you need to deploy it by passing control to Swift’s reference counting. There are two methods for this: takeRetainedValue () – returns the link with the decrement of the counter, and takeUnretainedValue () – just returns the reference.

16. Thread safety

In Swift, there is not yet any fundamental mechanism for thread safety. There are no atomic and nonatomic property modifiers from Objective-C. However, they are available as synchronization primitives like semaphores and mutexes, as well as Grand Central Dispatch and NSOperation from Cocoa.

17. Preprocessor

Unlike the Objective-C preprocessor, Swift does not. However, the Swift code can be compiled based on the condition of calculating build configurations. These settings can take into account the logical flasks of the compiler (-D <# flag #>) and the result of individual functions that can be checked by the OS – os () with an argument from the list: OSX, iOS, watchOS, tvOS, Linux; Architecture – arch (): x86_64, arm, arm64, i386; Version of the language – Swift ():> = and version number. To do this, the following directives are used: #if, #elseif, #else, #endif.
Apple docs.

18. Libraries of another language

Can I use Objective-C libraries and frameworks in Swift projects? Yes, until they require access to runtime to your pure Swift classes. For example, OCMock only works with Swift classes that are inherited from NSObject.

Can I use Swift libraries and frameworks in Objective-C projects? Only if they are designed in such a way as to support Objective-C. For Swift classes to be visible from Objective-C, they must be inherited from NSObject. Unique features for Swift will not be available.
Apple docs.

Dynamism Objective-C

When we talk about the momentum of Objective-C, we have in mind the following basic possibilities.

The application can recognize its structure in runtime. For example, what methods and properties are there for an object or getting a reference to a protocol, class, or method from a string.
The application can do something based on what it knows about its structure. For example, create instances of a class whose name was unknown at compile time, or access methods and properties that were not known at compile time either.
The application can change its structure. For example, in runtime, add methods to classes or declare new classes.

Using these features, Cocoa has implemented many useful mechanisms. In Swift, there is no such dynamism, but when we develop under iOS, we still stand on the shoulders of Cocoa and can use these possibilities, although with some limitations.

But after all, Swift is an open source language that exists not only in the Apple ecosystem, where there is Cocoa. These opportunities would be useful there. Also, although in the coming years, most likely, Cocoa will not go anywhere, we can assume that someday in the future Apple will replace the Cocoa framework with something new, written on pure Swift. How will they solve the problems that Objective-C solved with its dynamism? Consider some such dynamism-based features, as they are used in Swift + Cocoa, and what alternatives are in pure Swift.

19. “Target/action” messaging

“Target/action” messaging is used to send commands from the interface to the code. This ability to declare a method from an object in the responder chain and in one move to connect it to a UI element in Interface Builder in 1988 was an outstanding improvement over a single monolithic function that was called for any action from the user.

Swift + Cocoa. All responder classes are inherited from UIResponder of UIKit, so everything, of course, works.

In pure Swift, there is no self-analysis mechanism to implement such an opportunity. Without dynamism, you can not find which object in the responder chain implements a certain method in the runtime and call it. 

20. Key-Value Coding

The ability to access object properties using strings as identifiers.

Swift + Cocoa. In Swift, KVC only works for classes that are inherited from NSObject.

Alternatives to pure Swift?
Only read-only, through reflection using the Mirror structure. 

21. Key-Value Observing

Possibility to “subscribe” to updates of any property.

Swift + Cocoa. KVO only works if both the observer and the observed object are inherited from NSObject, and the observed property is marked as dynamic, to prevent static optimization.

There are no natural analogs in Swift, but, in principle, it is realizable, for example, with the help of property observers. Any implementation: its own or already ready library, for instance, Observable-Swift, adds extra code when using Cocoa KVO, everything worked as it is.

22. NotificationCenter

Ability to subscribe to notifications to one object, and to send other notifications to others.

Swift + Cocoa. Using the API with the selector imposes the following restrictions. The observer must be an instance of the class (not a structure or an enumeration) and the method called when receiving the notification must be accessible to Objective-C (the class is inherited from NSObject, or the method is marked with @objc). You can get rid of these restrictions using an API with a closure, but it still returns a token object of type NSObjectProtocol, with which you should unsubscribe from alerts. So the binding to Cocoa remains.

Pure Swift. To implement the “Observer” template, dynamism is not needed, so an analog in pure Swift can be applied. Moreover, the loss of the NS prefix in the name suggests that it is to be expected that NotificationCenter will be added to the Swift Foundation, that is, discard the Cocoa dynamism.

23. UndoManager

The ability to register changes as reversible to allow the user to navigate back and forth to them.

Swift + Cocoa. There are three ways to register changes: using the selector, through NSInvocation or the closure. All three methods are applicable only to instances of classes. For the method with the selector, there is an additional restriction: the same as described above about NotificationCenter: the method must be available for Objective-C. The method with NSInvocation is largely based on dynamism, because, in fact, it’s intercepting messages, so the class must inherit from NSObject. A method with a closure is available only starting with iOS 9.

Pure Swift. The existing UndoManager is based entirely on dynamism, but, like NotificationCenter, the implementation of such functionality is possible in pure Swift, and in the future, one should expect UndoManager in the Swift Foundation.
In general, all APIs with selectors for which dynamism is not necessary, that is, the called code is known at the time of compilation, can be replaced with a simple Swift API that uses closures or delegation.

For those tasks that depend on the dynamism of Objective-C, there are no solutions in pure Swift yet. How Swift solves these problems is not yet clear. Maybe it will be an addition of dynamism, perhaps in an entirely new way. It is important that this solution is not highly specialized, because when Objective-C was developed nobody knew about KVC, CoreData, bindings, HOM, UndoManager, etc. And none of this list required special language/compiler support. We want Swift not only to solve these problems but also do not limit us in developing new similar opportunities. [eleven]

Static typing in Swift

So what are the advantages of strict static typing in Swift? For what was lost dynamism?

1. Reliability. Write reliable code in Swift is easier than in Objective-C. Static typing makes it possible to use a type system to make unwanted behavior impossible. That is, catch possible errors at the compilation stage. Several interesting techniques can be looked at here: [12] and [13].

2. The speed of work? Of course, static binding allows the compiler to perform more aggressive optimization, and pure Swift works faster than Objective-C. But, unlikely, in iOS development you can get a significant benefit from this, while almost everything is based on the dynamic Cocoa.

Speaking of the type system, I would like to note the following. In Swift, no type is automatically cast to Bool, and the assignment operator does not return a value.

Conclusion

In addition to the capabilities of Swift and Objective-C distinguishes a few more points.

First, the source stability. Although the developers of the language tried to collect the maximum number of changes that violate compatibility in version 3.0, I think it’s no secret that Swift is still in active development, and such changes are unavoidable. However, now every proposal for such a change requires a convincing justification and detailed discussion. Also, to work with the old code base, a compiler flag for the language version and an extension for the Availability API will be added to the tongue. 

Secondly, Swift still does not have ABI compatibility. This means that dynamic libraries compiled in another version of the language will not work.

All this means that before you transfer your project to a new version of the language, you will have to wait until all the Swift libraries and frameworks that you use, too, will not switch to the new version.

Ensuring compatibility with Swift 3 and stabilizing ABI are the primary targets for Swift 4, which will be released in late 2017. 

And finally, the list of the moments that also distinguish Swift from Objective-C, but, in my opinion, do not influence development enough to make them into the main list.

Operator overload and the ability to identify new ones.
Reinforced switch-case.
Strict rules for initializers.
Indices (subscripts).
Availability API.
Playgrounds.
Swift – open source.
Type inference.
Intervals.
Option sets.
Labeled loops.
Auto closure.
String interpolation.

References

1. Advanced & Practical Enum usage in Swift
2. Controlling Complexity in Swift – or – Making Friends with Value Types
3. Protocols with Associated Types
4. Swift: Associated Types
5. The Ghost of Swift Bugs Future
6. Protocol-Oriented Programming in Swift
7. Unmanaged
8. A Definition of Dynamic Programming in the Cocoa World
9. Pimp My Code, Book 2: Swift and Dynamism
10. The Swift Reflection API and what you can do with it
11. What’s Missing in the Discussion about Dynamic Swift
12. The Type System is Your Friend
13. Enums as constants
14. Availability by Swift version
15. Looking back on Swift 3 and ahead to Swift 4