@Xiaojun-Jin
2014-09-15T12:07:06.000000Z
字数 10402
阅读 1899
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 = 70
let explicitDouble: Double = 70
let 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 = 0
for score in individualScores
{
if score > 50
{
teamScore += 3
}
else
{
teamScore += 1
}
}
println(teamScore)
let vegetable = "red pepper"
var vegetableComment: String
switch 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 arguments
func greet(name: String, day: String) -> String
{
return "Hello \(name), today is \(day)."
}
println(greet("Bob", "Tuesday"))
// func with multiple return values
func getGasPrices() -> (Double, Double, Double)
{
return (3.59, 3.69, 3.79)
}
println(getGasPrices())
// variable number of arguments
func sumOf(numbers: Int...) -> Int
{
var sum = 0
for number in numbers
{
sum += number
}
return sum
}
println(sumOf())
println(sumOf(42, 597, 12))
// return another func as its value
func 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 arguments
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]
println(hasAnyMatches(numbers, lessThanTen))
class Shape
{
var numberOfSides = 0
func simpleDescription() -> String
{
return "A shape with \(numberOfSides) sides."
}
}
var shape = Shape()
shape.numberOfSides = 7
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.
class NamedShape
{
var numberOfSides: Int = 0
var name: String
init(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: 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")
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.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 / 2.0
}
}
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
println(triangle.perimeter)
triangle.perimeter = 10
println(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: String
println(strT)
var strT: String?
println(strT)
var value:Int?
println(value)
var value:Int = nil // incorrect
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".
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?.sideLength
let sideLengthA = optionalSquare!.sideLength
println(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 = 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()
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, 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
println(hearts.simpleDescription())
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)
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 = 69105
func 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 themutating
keyword when writing an implementation of that method for a class. Themutating
keyword 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 = 7
number.adjust()
println(number.simpleDescription)
func swapTwoInts(inout a: Int, inout b: Int)
{
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
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.
// using <> to make a generic type
func swapTwoValues<T>(inout a: T, inout b: T)
{
let temporaryA = a
a = b
b = 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 None
case Some(T)
}
var possibleInteger: OptionalValue<Int> = .None
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.
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.