“Hello, world”
. With Swift, this is done like this: println("Hello, world")
main
function is no longer needed. Also note the absence of a semicolon at the end of each line.Comment
For a better understanding of the material, we recommend using the playground mode in Xcode. Playground allows you to see the result immediately in the code editing process without having to compile and run the application.
let
to create a constant and var
to create a variable. You don't need to specify a constant type; you can assign a value to it only once. var myVariable = 42 myVariable = 50 let myConstant = 42
myVariable
is of integer type. let implicitInteger = 70 let inplicitDouble = 70.0 let inplicitDouble: Double = 70
Let's experiment
Create a constant with type Float and initialize it with the number 4.
let label = "The width is " let width = 94 let widthLabel = label + String(width)
Let's experiment
Try removing the explicit conversion to the String type in the last line. What error do you get?
\
) in front of them. Example: let apples = 3 let oranges = 5 let appleSummary = "I have \(apples) apples." let fruitSummary = "I have \(apples + oranges) pieces of fruit."
Let's experiment
Try using the\()
construct and display a string that includes the result of the sum of two integer variables and someone's name.
[]
) are used: var shoppingList = ["catfish", "water", "tulips", "blue paint"] shoppingList[1] = "bottle of water" var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic", ] occupations["Jayne"] = "Public Relations"
let emptyArray = String[]() let emptyDictionary = Dictionary<String, Float>()
[]
and [:]
respectively, for example, when you assign a new value to a variable or pass an argument to a function. shoppingList = [] // Went shopping and bought everything.
if
and switch
, to create loops - for-in
, for
, while
and do-while
. In this case, it is not necessary to select conditions and initializing expressions in parentheses, while curly brackets are required. let individualScores = [75, 43, 103, 87, 12] var teamScore = 0 for score in individualScores { if score > 50 { teamScore += 3 } else { teamScore += 1 } } teamScore
if
should be logical, which in particular means that the expression if score {…}
is erroneous, since there is no explicit comparison (for example, with zero).if
can be used in conjunction with let
and var
to work with constants and variables that can be nil
. Such constants and variables are called optional (that is, they can either take a value or be equal to nil
). To create an optional variable or constant add a question mark ( ?
) After specifying the type. var optionalString: String? = "Hello" optionalString == nil var optionalName: String? = "John Appleseed" var greeting = "Hello!" if let name = optionalName { greeting = "Hello, \(name)" }
Let's experiment
ChangeoptionalName
tonil
. What do you see on the screen? Add anelse
block to handle the case whenoptionalName
isnil
.
nil
, the condition will be false and the code in braces after the if
will not be executed. Otherwise, the variable greeting
will be assigned a new value.switch
multiple select switch
supports many other comparison operators within it and is not limited to simple comparisons: let vegetable = "red pepper" switch vegetable { case "celery": let vegetableComment = "Add some raisins and make ants on a log." case "cucumber", "watercress": let vegetableComment = "That would make a good tea sandwich." case let x where x.hasSuffix("pepper"): let vegetableComment = "Is it a spicy \(x)?" default: let vegetableComment = "Everything tastes good in soup." }
Let's experiment
Try removing the default condition. What error do you get?
switch
without checking the subsequent conditions. Thus, you do not need to manually add interrupts ( break
) at the end of each case
block.for-in
operator along with a pair of names for each key-value pair. let interestingNumbers = [ "Prime": [2, 3, 5, 7, 11, 13], "Fibonacci": [1, 1, 2, 3, 5, 8], "Square": [1, 4, 9, 16, 25], ] var largest = 0 for (kind, numbers) in interestingNumbers { for number in numbers { if number > largest { largest = number } } } largest
Let's experiment
Add another variable that will allow you to find out which of the three types the maximum number found is.
while
operator allows you to execute a block of code inside it until the condition becomes false. The condition can also be specified after the block, which in this case will be executed at least once. var n = 2 while n < 100 { n = n * 2 } n var m = 2 do { m = m * 2 } while m < 100 m
..
) or using an initializer, condition, and increment. Look, these two cycles do the same thing: var firstForLoop = 0 for i in 0..3 { firstForLoop += i } firstForLoop var secondForLoop = 0 for var i = 0; i < 3; ++i { secondForLoop += 1 } secondForLoop
..
) if you do not want to include a larger value in the range, and three points ( …
) to include both smaller and larger values.func
keyword. The function is called by specifying its name and the list of arguments in parentheses. The return type should be separated from the list of formal arguments with ->
. func greet(name: String, day: String) -> String { return "Hello \(name), today is \(day)." } greet("Bob", "Tuesday")
Let's experiment
Remove the day parameter. Instead, add a variable denoting the name of the dish served for lunch.
func getGasPrices() -> (Double, Double, Double) { return (3.59, 3.69, 3.79) } getGasPrices()
func sumOf(numbers: Int...) -> Int { var sum = 0 for number in numbers { sum += number } return sum } sumOf() sumOf(42, 597, 12)
Let's experiment
Write a function that allows you to find the arithmetic mean of an arbitrary number of its arguments.
func returnFifteen() -> Int { var y = 10 func add() { y += 5 } add() return y } returnFifteen()
func makeIncrementer() -> (Int -> Int) { func addOne(number: Int) -> Int { return 1 + number } return addOne } var increment = makeIncrementer() increment(7)
func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool { for item in list { if condition(item) { return true } } return false } func lessThanTen(number: Int) -> Bool { return number < 10 } var numbers = [20, 19, 7, 12] hasAnyMatches(numbers, lessThanTen)
{}
). To separate the arguments and return type from the closure body, use the in
operator. numbers.map({ (number: Int) -> Int in let result = 3 * number return result })
Let's experiment
Rewrite the closure so that it returns zero for all unnecessary numbers.
numbers.map({ number in 3 * number })
sort([1, 5, 3, 12, 2]) { $0 > $1 }
class
. Class members are declared in the same way as regular constants and variables. Moreover, class methods are declared as ordinary functions. class Shape { var numberOfSides = 0 func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
Let's experiment
Add a class constant member and a class method that takes it as its argument.
var shape = Shape() shape.numberOfSides = 7 var shapeDescription = shape.simpleDescription()
init
method. class NamedShape { var numberOfSides: Int = 0 var name: String init(name: String) { self.name = name } func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
self
is separated from the argument of the name
constructor. Arguments are passed to the constructor in the usual way, as in any other class method. Note that each member of the class must be initialized — either when declaring (as, for example, numberOfSides
), or in the constructor (as name
).deinit
method, which can be rewritten if necessary.override
child class must be marked with the override
keyword — overriding methods without override will result in an error. The compiler also identifies methods labeled override
, but not overriding any methods of their parent class. class Square: NamedShape { var sideLength: Double init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 4 } func area() -> Double { return sideLength * sideLength } override func simpleDescription() -> String { return "A square with sides of length \(sideLength)." } } let test = Square(sideLength: 5.2, name: "my test square") test.area() test.simpleDescription()
Let's experiment
Create aCircle
class and inherit it from theNamedShape
class. The constructor of theCircle
class takes two arguments, the radius and the name. Overridearea
methods anddescribe
this class.
getter
and setter
. class EquilateralTriangle: NamedShape { var sideLength: Double = 0.0 init(sideLength: Double, name: String) { self.sideLength = sideLength super.init(name: name) numberOfSides = 3 } var perimeter: Double { get { return 3.0 * sideLength } set { sideLength = newValue / 3.0 } } override func simpleDescription() -> String { return "An equilateral triagle with sides of length \(sideLength)." } } var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle") triangle.perimeter triangle.perimeter = 9.9 triangle.sideLength
setter
perimeter
variable perimeter
new value assigned is implicitly called newValue
. You can change the name of this variable by specifying it in brackets immediately after set
.EquilateralTriangle
class. This method involves three consecutive steps:willSet
and didSet
methods in the way you want. For example, in the class below, it is guaranteed that the length of the side of the triangle will always be equal to the length of the side of the square. class TriangleAndSquare { var triangle: EquilateralTriangle { willSet { square.sideLength = newValue.sideLength } } var square: Square { willSet { triangle.sideLength = newValue.sideLength } } init(size: Double, name: String) { square = Square(sideLength: size, name: name) triangle = EquilateralTriangle(sideLength: size, name: name) } } var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape") triangleAndSquare.square.sideLength triangleAndSquare.triangle.sideLength triangleAndSquare.square = Square(sideLength: 50, name: "larger square") triangleAndSquare.triangle.sideLength
times
) that will be used only inside this method. In this case, to call this method, you must use the first name ( numberOfTimes
). class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes times: Int) { count += amount * times } } var counter = Counter() counter.incrementBy(2, numberOfTimes: 7)
?
) Before methods, class members, etc. If the value before the question mark is nil
, everything that follows ( ?
) ?
ignored and the value of the whole expression is nil
. Otherwise, the expression is evaluated in the usual way. In both cases, the result of the entire expression is an optional value. let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") let sideLength = optionalSquare?.sideLength
enum
keyword is used to create enum
. Note that enumerations can also include methods. enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten case Jack, Queen, King func simpleDescription() -> String { switch self { case .Ace: return "ace" case .Jack: return "jack" case .Queen: return "queen" case .King: return "king" default: return String(self.toRaw()) } } } let ace = Rank.Ace let aceRawValue = ace.toRaw()
Let's experiment
Write a function that compares 2Rank
type listings by their values.
toRaw
and fromRaw
. if let convertedRank = Rank.fromRaw(3) { let threeDescription = convertedRank.simpleDescription() }
enum Suit { case Spades, Hearts, Diamonds, Clubs func simpleDescription() -> String { switch self { case .Spades: return "spades" case .Hearts: return "hearts" case .Diamonds: return "diamonds" case .Clubs: return "clubs" } } } let hearts = Suit.Hearts let heartsDescription = hearts.simpleDescription()
Let's experiment
Add aColor
method that returns the string“black”
forSpades
andClubs
and“red”
forHearts
andDiamonds
.
Hearts
member accesses the Suit
enumeration. When assigning a value to the constant of hearts
, the full name Suit.Hearts
, since we obviously do not indicate the type of this constant. And in switch
we use the abbreviated form .Hearts
, since the type of self
is known a priori. You can use the short form everywhere if the variable type is explicitly specified.struct
keyword is used to create structures. Structures have many similar features with classes, including methods and constructors. One of the most significant differences between structures and classes is that instances of structures, unlike instances of classes, are passed to functions by value (that is, they create a local copy first), while instances of classes are passed by reference. struct Card { var rank: Rank var suit: Suit func simpleDescription() -> String { return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" } } let threeOfSpades = Card(rank: .Three, suit: .Spades) let threeOfSpadesDescription = threeOfSpades.simpleDescription()
Let's experiment
Add a method to the Card structure that creates a complete deck of cards.
success
constant in the example). Associated and initial values are different things: the initial value of an enumeration member is always constant for all instances of the enumeration and is indicated when it is declared. enum ServerResponse { case Result(String, String) case Error(String) } let success = ServerResponse.Result("6:00 am", "8:09 pm") let failure = ServerResponse.Error("Out of cheese.") switch success { case let .Result(sunrise, sunset): let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)." case let .Error(error): let serverResponse = "Failure... \(error)" }
Let's experiment
Add a third option to theswitch
multiple selectswitch
ServerResponse
object. protocol ExampleProtocol { var simpleDescription: String { get } mutating func adjust() }
class SimpleClass: ExampleProtocol { var simpleDescription: String = "A very simple class." var anotherProperty: Int = 69105 func adjust() { simpleDescription += " Now 100% adjusted." } } var a = SimpleClass() a.adjust() let aDescription = a.simpleDescription struct SimpleStructure: ExampleProtocol { var simpleDescription: String = "A simple structure" mutating func adjust() { simpleDescription += " (adjusted)" } } var b = SimpleStructure() b.adjust() let bDescription = b.simpleDescription
Let's experiment
Create an enumeration that will implement this protocol.
mutating
keyword in the definition of the SimpleStructure
structure, which informs the compiler that the corresponding method SimpleStructure
structure change. In contrast, SimpleClass
class SimpleClass
do not need to be labeled as mutating
, since class methods can always change it freely.extensions
. You can also use extensions to implement a protocol of an already existing type, even if it is imported from any library or framework. extension Int: ExampleProtocol { var simpleDescription: String { return "The number \(self)" } mutating func adjust() { self += 42 } } 7.simpleDescription
Let's experiment
Create a type extensionDouble
with a member variableabsoluteValue
.
let protocolValue: ExampleProtocol = a protocolValue.simpleDescription // protocolValue.anotherProperty // Uncomment to see the error
protocolValue
is of type SimpleClass
, the compiler assumes that its type is ExampleProtocol
. This means that you cannot accidentally gain access to methods or members of a class that are implemented outside the protocol ExampleProtocol
.<>
). func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] { var result = ItemType[]() for i in 0..times { result += item } return result } repeat("knock", 4)
// Reimplement the Swift standard library's optional type enum OptionalValue<T> { case None case Some(T) } var possibleInteger: OptionalValue<Int> = .None possibleInteger = .Some(100)
where
. func anyCommonElements <T, U where T: Sequence, U: Sequence, T.GeneratorType.Element: Equatable, T.GeneratorType.Element == U.GeneratorType.Element> (lhs: T, rhs: U) -> Bool { for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { return true } } } return false } anyCommonElements([1, 2, 3], [3])
Let's experiment.
Modify the functionanyCommonElements
so that it returns an array of common elements.
where
and write the name of the protocol or class after the colon. An expression is <T: Equatable>
equivalent to an expression <T where T: Equatable>
.Source: https://habr.com/ru/post/225841/
All Articles