[关闭]
@Xiaojun-Jin 2014-09-15T12:07:06.000000Z 字数 10402 阅读 1899

Introduction to Swift Programming Language

iOS Swift


Swift is a new brand programming language introduced by Apple at this year's WWDC. We are compelled to have a grasp of it as we are choosing to write iOS code for a living (just kidding O(∩_∩)O). Apple has released an excellent Swift Tutorial, which I highly recommend you taking a look. Now let's get started with Swift tour.

Variables and Constants

  1. let implicitInt = 70
  2. let explicitDouble: Double = 70
  3. let label = "The width is "
  4. let labelW = label + String(implicitInt)
  5. println(labelW)
  6. let appleSummary = "I have \(explicitDouble) apples."
  7. println(appleSummary)
  1. var shoppingList = ["catfish", "water", "tulips", "blue paint"]
  2. shoppingList[1] = "bottle of water"
  3. var occupations =
  4. [
  5. "Malcolm": "Captain",
  6. "Kaylee": "Mechanic",
  7. ]
  8. occupations["Jayne"] = "Public Relations"
  9. occupations["Stephen"] = "Oh, YES!"

To create an empty array or dictionary, use the initializer syntax:

  1. let emptyArray = [String]()
  2. let emptyDictionary = [String: Float]()

Control Flow

  1. let individualScores = [75, 43, 103, 87, 12]
  2. var teamScore = 0
  3. for score in individualScores
  4. {
  5. if score > 50
  6. {
  7. teamScore += 3
  8. }
  9. else
  10. {
  11. teamScore += 1
  12. }
  13. }
  14. println(teamScore)
  1. let vegetable = "red pepper"
  2. var vegetableComment: String
  3. switch vegetable
  4. {
  5. case "celery":
  6. vegetableComment = "Add some raisins and make ants on a log."
  7. case "cucumber", "watercress":
  8. vegetableComment = "That would make a good tea sandwich."
  9. case let x where x.hasSuffix("pepper"):
  10. vegetableComment = "Is it a spicy \(x)?"
  11. default:
  12. vegetableComment = "Everything tastes good in soup."
  13. }
  14. println(vegetableComment)

Functions Definition

  1. // func with two arguments
  2. func greet(name: String, day: String) -> String
  3. {
  4. return "Hello \(name), today is \(day)."
  5. }
  6. println(greet("Bob", "Tuesday"))
  1. // func with multiple return values
  2. func getGasPrices() -> (Double, Double, Double)
  3. {
  4. return (3.59, 3.69, 3.79)
  5. }
  6. println(getGasPrices())
  1. // variable number of arguments
  2. func sumOf(numbers: Int...) -> Int
  3. {
  4. var sum = 0
  5. for number in numbers
  6. {
  7. sum += number
  8. }
  9. return sum
  10. }
  11. println(sumOf())
  12. println(sumOf(42, 597, 12))
  1. // return another func as its value
  2. func makeIncrementer() -> (Int -> Int)
  3. {
  4. func addOne(number: Int) -> Int
  5. {
  6. return 1 + number
  7. }
  8. return addOne
  9. }
  10. var increment = makeIncrementer()
  11. println(increment(7))
  1. // func takes another function as one of its arguments
  2. func hasAnyMatches(list: [Int], condition: Int -> Bool) -> Bool
  3. {
  4. for item in list
  5. {
  6. if condition(item)
  7. {
  8. return true
  9. }
  10. }
  11. return false
  12. }
  13. func lessThanTen(number: Int) -> Bool
  14. {
  15. return number < 10
  16. }
  17. var numbers = [20, 19, 7, 12]
  18. println(hasAnyMatches(numbers, lessThanTen))

Objects and Classes

  1. class Shape
  2. {
  3. var numberOfSides = 0
  4. func simpleDescription() -> String
  5. {
  6. return "A shape with \(numberOfSides) sides."
  7. }
  8. }
  9. var shape = Shape()
  10. shape.numberOfSides = 7
  11. println(shape.simpleDescription())

Use init to set up the class when an instance is created and implement deinit to create a deinitializer if you need to perform some cleanup before the object is deallocated.

  1. class NamedShape
  2. {
  3. var numberOfSides: Int = 0
  4. var name: String
  5. init(name: String)
  6. {
  7. self.name = name
  8. }
  9. func simpleDescription() -> String
  10. {
  11. return "A shape named \(self.name) with \(numberOfSides) sides."
  12. }
  13. deinit
  14. {
  15. println("I am dead!")
  16. }
  17. }
  18. var nameShape = NamedShape(name: "Stephen")
  19. println(nameShape.simpleDescription())
  1. class Square: NamedShape
  2. {
  3. var sideLength: Double
  4. init(sideLength: Double, name: String)
  5. {
  6. self.sideLength = sideLength
  7. super.init(name: name)
  8. numberOfSides = 4
  9. }
  10. func area() -> Double
  11. {
  12. return sideLength * sideLength
  13. }
  14. override func simpleDescription() -> String
  15. {
  16. return "A square with sides of length \(sideLength)."
  17. }
  18. }
  19. let test = Square(sideLength: 5.2, name: "my test square")
  20. println(test.area())
  21. println(test.simpleDescription())

So far so good, but wait a minute, aren't you curious about how to create and display a UILabel using Swift based on the Class and Object methods we described above? Let's show you how to implement this:

  1. var swiftLabel = UILabel(frame: CGRectMake(0, 200, 320, 100))
  2. swiftLabel.text = "Swift"
  3. swiftLabel.font = UIFont.systemFontOfSize(50);
  4. swiftLabel.textAlignment = NSTextAlignment.Center;
  5. swiftLabel.textColor = UIColor.blueColor()
  6. self.view.addSubview(swiftLabel);
  1. class EquilateralTriangle: NamedShape
  2. {
  3. var sideLength: Double = 0.0
  4. init(sideLength: Double, name: String)
  5. {
  6. self.sideLength = sideLength
  7. super.init(name: name)
  8. numberOfSides = 3
  9. }
  10. var perimeter: Double {
  11. get {
  12. return 3.0 * sideLength
  13. }
  14. set {
  15. sideLength = newValue / 2.0
  16. }
  17. }
  18. }
  19. var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
  20. println(triangle.perimeter)
  21. triangle.perimeter = 10
  22. println(triangle.perimeter)
  1. class TriangleAndSquare
  2. {
  3. var triangle: EquilateralTriangle {
  4. willSet {
  5. square.sideLength = newValue.sideLength
  6. }
  7. }
  8. var square: Square {
  9. willSet {
  10. triangle.sideLength = newValue.sideLength
  11. }
  12. }
  13. init(size: Double, name: String)
  14. {
  15. square = Square(sideLength: size, name: name)
  16. triangle = EquilateralTriangle(sideLength: size, name: name)
  17. }
  18. }
  19. var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
  20. println(triangleAndSquare.square.sideLength)
  21. println(triangleAndSquare.triangle.sideLength)
  22. triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
  23. println(triangleAndSquare.triangle.sideLength)

Optional Values

An optional value either contains a value or contains nil to indicate that the value is missing. Write a question mark (?) after the type of a value to mark the value as optional.

  1. var str: String? // set str's initial value to nil

Swift's nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a non-existent object. In Swift, nil is not a pointer - it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types.

Try to test the following code in Xcode 6 and you'll understand optional value's meaning in a more concrete manner according to the running result.

  1. var strT: String
  2. println(strT)
  3. var strT: String?
  4. println(strT)
  1. var value:Int?
  2. println(value)
  3. var value:Int = nil // incorrect
  4. var value:Int? = nil // correct

In my opinion, the variable will have two option values involved if it is marked as option value upon creating. For instance, the values of strO defined below including "nil" and "Hello World".

  1. var strO: String? = "Hello World!"
  2. println(strO)
  3. println(strO!)

The option value must be unwrapped before accessing its content (adding symbol '!' right after the variable). In adition, the option value gets unwrapped implicitly when working with control flow statements such as if and switch.

  1. var optionalName:String? = "John Appleseed"
  2. var greeting = "Hello!"
  3. if let name = optionalName // implicit unwrapping
  4. {
  5. println("optionalName = \(optionalName)")
  6. println("name = \(name)")
  7. greeting = "Hello \(name)"
  8. }
  9. println("greeting = \(greeting)")
  1. let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
  2. let sideLength = optionalSquare?.sideLength
  3. let sideLengthA = optionalSquare!.sideLength
  4. println(sideLength)
  5. println(sideLengthA)

Enumerations and Structures

In Swift we use enum to create an enumeration. Like classes and all other named types, enumerations can have methods associated with them.

  1. enum Rank: Int
  2. {
  3. case Ace = 1
  4. case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
  5. case Jack, Queen, King
  6. func simpleDescription() -> String
  7. {
  8. switch self
  9. {
  10. case .Ace:
  11. return "ace"
  12. case .Jack:
  13. return "jack"
  14. case .Queen:
  15. return "queen"
  16. case .King:
  17. return "king"
  18. default:
  19. return String(self.toRaw())
  20. }
  21. }
  22. }
  23. let ace = Rank.Ace
  24. let aceRawValue = ace.toRaw()
  25. println(aceRawValue)
  26. println(ace.simpleDescription())
  1. if let convertedRank = Rank.fromRaw(3)
  2. {
  3. let threeDescription = convertedRank.simpleDescription()
  4. println(threeDescription)
  5. }

The member values of an enumeration are actual values, not just another way of writing their raw values. In fact, in cases where there isn't a meaningful raw value, you don't have to provide one. For example:

  1. enum Suit
  2. {
  3. case Spades, Hearts, Diamonds, Clubs
  4. func simpleDescription() -> String
  5. {
  6. switch self
  7. {
  8. case .Spades:
  9. return "spades"
  10. case .Hearts:
  11. return "hearts"
  12. case .Diamonds:
  13. return "diamonds"
  14. case .Clubs:
  15. return "clubs"
  16. }
  17. }
  18. }
  19. let hearts = Suit.Hearts
  20. println(hearts.simpleDescription())

  1. struct Card
  2. {
  3. var rank: Rank
  4. var suit: Suit
  5. func simpleDescription() -> String
  6. {
  7. return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
  8. }
  9. }
  10. let threeOfSpades = Card(rank: .Three, suit: .Spades)
  11. println(threeOfSpades.simpleDescription())

An instance of an enumeration member can have values associated with the instance. You provide the associated values when you create the instance.

  1. enum Barcode
  2. {
  3. case UPCA(Int, Int, Int)
  4. case QRCode(String)
  5. }
  6. var productBarcode = Barcode.UPCA(8, 85909_51226, 3)
  7. productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
  8. switch productBarcode
  9. {
  10. case .UPCA(let numberSystem, let identifier, let check):
  11. println("UPC-A with value of \(numberSystem), \(identifier), \(check).")
  12. case .QRCode(let productCode):
  13. println("QR code with value of \(productCode).")
  14. }

You can extract each associated value as a constant (with the let prefix) or a variable (with the var prefix) for use within the switch case's body. For brevity, it allows to write as this format:

  1. case let .UPCA(numberSystem, identifier, check):

Here you'll see a warning: "Switch condition evaluates to a constant". To remove this warning, simply put the variable's (productBarcode) declaration out of the function.

Protocols and Extensions

  1. protocol ExampleProtocol
  2. {
  3. var simpleDescription: String { get }
  4. mutating func adjust()
  5. }
  1. class SimpleClass: ExampleProtocol
  2. {
  3. var simpleDescription: String = "A very simple class."
  4. var anotherProperty: Int = 69105
  5. func adjust()
  6. {
  7. simpleDescription += " Now 100% adjusted."
  8. }
  9. }
  10. var a = SimpleClass()
  11. a.adjust()
  12. println(a.simpleDescription)

If you mark a protocol instance method requirement as mutating, you do not need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations. Check out detailed explanation here.

  1. struct SimpleStructure: ExampleProtocol
  2. {
  3. var simpleDescription: String = "A simple structure"
  4. mutating func adjust()
  5. {
  6. simpleDescription += " (adjusted)"
  7. }
  8. }
  9. var b = SimpleStructure()
  10. b.adjust()
  11. println(b.simpleDescription)

  1. extension Int: ExampleProtocol
  2. {
  3. var simpleDescription: String
  4. {
  5. return "The number \(self)"
  6. }
  7. mutating func adjust()
  8. {
  9. self += 42
  10. }
  11. }
  1. println(7.simpleDescription)
  2. var number: Int = 7
  3. number.adjust()
  4. println(number.simpleDescription)

Generics

  1. func swapTwoInts(inout a: Int, inout b: Int)
  2. {
  3. let temporaryA = a
  4. a = b
  5. b = temporaryA
  6. }
  7. var someInt = 3
  8. var anotherInt = 107
  9. swapTwoInts(&someInt, &anotherInt)

If you want a function to modify a parameter's value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.

  1. // using <> to make a generic type
  2. func swapTwoValues<T>(inout a: T, inout b: T)
  3. {
  4. let temporaryA = a
  5. a = b
  6. b = temporaryA
  7. }
  8. var someString = "hello"
  9. var anotherString = "world"
  10. swapTwoValues(&someString, &anotherString)

We can make generic forms of functions and methods, as well as classes, enumerations, and structures.

  1. func repeat<ItemType>(item: ItemType, times: Int) -> [ItemType]
  2. {
  3. var result = [ItemType]()
  4. for i in 0..<times
  5. {
  6. result.append(item)
  7. }
  8. return result
  9. }
  10. println(repeat("knock", 4))
  1. enum OptionalValue<T>
  2. {
  3. case None
  4. case Some(T)
  5. }
  6. var possibleInteger: OptionalValue<Int> = .None
  7. possibleInteger = .Some(100)

Use where after the type name to specify a list of requirements - for example, to require the type to implement a protocol, to require two types to be the same, or to require a class to have a particular superclass.

  1. func anyCommonElements <T, U where T: SequenceType, U: SequenceType,
  2. T.Generator.Element: Equatable,
  3. T.Generator.Element == U.Generator.Element>
  4. (lhs: T, rhs: U) -> Bool
  5. {
  6. for lhsItem in lhs
  7. {
  8. for rhsItem in rhs
  9. {
  10. if lhsItem == rhsItem
  11. {
  12. return true
  13. }
  14. }
  15. }
  16. return false
  17. }
  18. println(anyCommonElements([1, 2, 3], [3]))

You can download the sample code associated with this post from my GitHub page linked here.

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注