@Xiaojun-Jin
2014-09-15T12:07:06.000000Z
字数 10402
阅读 2025
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.
let implicitInt = 70let explicitDouble: Double = 70let label = "The width is "let labelW = label + String(implicitInt)println(labelW)let appleSummary = "I have \(explicitDouble) apples."println(appleSummary)
var shoppingList = ["catfish", "water", "tulips", "blue paint"]shoppingList[1] = "bottle of water"var occupations =["Malcolm": "Captain","Kaylee": "Mechanic",]occupations["Jayne"] = "Public Relations"occupations["Stephen"] = "Oh, YES!"
To create an empty array or dictionary, use the initializer syntax:
let emptyArray = [String]()let emptyDictionary = [String: Float]()
let individualScores = [75, 43, 103, 87, 12]var teamScore = 0for score in individualScores{if score > 50{teamScore += 3}else{teamScore += 1}}println(teamScore)
let vegetable = "red pepper"var vegetableComment: Stringswitch vegetable{case "celery":vegetableComment = "Add some raisins and make ants on a log."case "cucumber", "watercress":vegetableComment = "That would make a good tea sandwich."case let x where x.hasSuffix("pepper"):vegetableComment = "Is it a spicy \(x)?"default:vegetableComment = "Everything tastes good in soup."}println(vegetableComment)
// func with two argumentsfunc greet(name: String, day: String) -> String{return "Hello \(name), today is \(day)."}println(greet("Bob", "Tuesday"))
// func with multiple return valuesfunc getGasPrices() -> (Double, Double, Double){return (3.59, 3.69, 3.79)}println(getGasPrices())
// variable number of argumentsfunc sumOf(numbers: Int...) -> Int{var sum = 0for number in numbers{sum += number}return sum}println(sumOf())println(sumOf(42, 597, 12))
// return another func as its valuefunc makeIncrementer() -> (Int -> Int){func addOne(number: Int) -> Int{return 1 + number}return addOne}var increment = makeIncrementer()println(increment(7))
// func takes another function as one of its argumentsfunc 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]println(hasAnyMatches(numbers, lessThanTen))
class Shape{var numberOfSides = 0func simpleDescription() -> String{return "A shape with \(numberOfSides) sides."}}var shape = Shape()shape.numberOfSides = 7println(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.
class NamedShape{var numberOfSides: Int = 0var name: Stringinit(name: String){self.name = name}func simpleDescription() -> String{return "A shape named \(self.name) with \(numberOfSides) sides."}deinit{println("I am dead!")}}var nameShape = NamedShape(name: "Stephen")println(nameShape.simpleDescription())
class Square: NamedShape{var sideLength: Doubleinit(sideLength: Double, name: String){self.sideLength = sideLengthsuper.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")println(test.area())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:
var swiftLabel = UILabel(frame: CGRectMake(0, 200, 320, 100))swiftLabel.text = "Swift"swiftLabel.font = UIFont.systemFontOfSize(50);swiftLabel.textAlignment = NSTextAlignment.Center;swiftLabel.textColor = UIColor.blueColor()self.view.addSubview(swiftLabel);
class EquilateralTriangle: NamedShape{var sideLength: Double = 0.0init(sideLength: Double, name: String){self.sideLength = sideLengthsuper.init(name: name)numberOfSides = 3}var perimeter: Double {get {return 3.0 * sideLength}set {sideLength = newValue / 2.0}}}var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")println(triangle.perimeter)triangle.perimeter = 10println(triangle.perimeter)
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")println(triangleAndSquare.square.sideLength)println(triangleAndSquare.triangle.sideLength)triangleAndSquare.square = Square(sideLength: 50, name: "larger square")println(triangleAndSquare.triangle.sideLength)
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.
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.
var strT: Stringprintln(strT)var strT: String?println(strT)
var value:Int?println(value)var value:Int = nil // incorrectvar 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".
var strO: String? = "Hello World!"println(strO)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.
var optionalName:String? = "John Appleseed"var greeting = "Hello!"if let name = optionalName // implicit unwrapping{println("optionalName = \(optionalName)")println("name = \(name)")greeting = "Hello \(name)"}println("greeting = \(greeting)")
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")let sideLength = optionalSquare?.sideLengthlet sideLengthA = optionalSquare!.sideLengthprintln(sideLength)println(sideLengthA)
In Swift we use enum to create an enumeration. Like classes and all other named types, enumerations can have methods associated with them.
enum Rank: Int{case Ace = 1case Two, Three, Four, Five, Six, Seven, Eight, Nine, Tencase Jack, Queen, Kingfunc 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.Acelet aceRawValue = ace.toRaw()println(aceRawValue)println(ace.simpleDescription())
if let convertedRank = Rank.fromRaw(3){let threeDescription = convertedRank.simpleDescription()println(threeDescription)}
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:
enum Suit{case Spades, Hearts, Diamonds, Clubsfunc simpleDescription() -> String{switch self{case .Spades:return "spades"case .Hearts:return "hearts"case .Diamonds:return "diamonds"case .Clubs:return "clubs"}}}let hearts = Suit.Heartsprintln(hearts.simpleDescription())
struct Card{var rank: Rankvar suit: Suitfunc simpleDescription() -> String{return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"}}let threeOfSpades = Card(rank: .Three, suit: .Spades)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.
enum Barcode{case UPCA(Int, Int, Int)case QRCode(String)}var productBarcode = Barcode.UPCA(8, 85909_51226, 3)productBarcode = .QRCode("ABCDEFGHIJKLMNOP")switch productBarcode{case .UPCA(let numberSystem, let identifier, let check):println("UPC-A with value of \(numberSystem), \(identifier), \(check).")case .QRCode(let productCode):println("QR code with value of \(productCode).")}
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:
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.
protocol ExampleProtocol{var simpleDescription: String { get }mutating func adjust()}
class SimpleClass: ExampleProtocol{var simpleDescription: String = "A very simple class."var anotherProperty: Int = 69105func adjust(){simpleDescription += " Now 100% adjusted."}}var a = SimpleClass()a.adjust()println(a.simpleDescription)
If you mark a protocol instance method requirement as
mutating, you do not need to write themutatingkeyword when writing an implementation of that method for a class. Themutatingkeyword is only used by structures and enumerations. Check out detailed explanation here.
struct SimpleStructure: ExampleProtocol{var simpleDescription: String = "A simple structure"mutating func adjust(){simpleDescription += " (adjusted)"}}var b = SimpleStructure()b.adjust()println(b.simpleDescription)
extension Int: ExampleProtocol{var simpleDescription: String{return "The number \(self)"}mutating func adjust(){self += 42}}
println(7.simpleDescription)var number: Int = 7number.adjust()println(number.simpleDescription)
func swapTwoInts(inout a: Int, inout b: Int){let temporaryA = aa = bb = temporaryA}var someInt = 3var anotherInt = 107swapTwoInts(&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-outparameter instead.
// using <> to make a generic typefunc swapTwoValues<T>(inout a: T, inout b: T){let temporaryA = aa = bb = temporaryA}var someString = "hello"var anotherString = "world"swapTwoValues(&someString, &anotherString)
We can make generic forms of functions and methods, as well as classes, enumerations, and structures.
func repeat<ItemType>(item: ItemType, times: Int) -> [ItemType]{var result = [ItemType]()for i in 0..<times{result.append(item)}return result}println(repeat("knock", 4))
enum OptionalValue<T>{case Nonecase Some(T)}var possibleInteger: OptionalValue<Int> = .NonepossibleInteger = .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.
func anyCommonElements <T, U where T: SequenceType, U: SequenceType,T.Generator.Element: Equatable,T.Generator.Element == U.Generator.Element>(lhs: T, rhs: U) -> Bool{for lhsItem in lhs{for rhsItem in rhs{if lhsItem == rhsItem{return true}}}return false}println(anyCommonElements([1, 2, 3], [3]))
You can download the sample code associated with this post from my GitHub page linked here.