按照惯例,我们一般学习一个新语言的时候,我们都习惯性的在屏幕上打印“Hello, World”,在Swift中,你可以用如下一个单独语句实现
println("Hello,World")
这个案例将给你足够的信息去开始swift代码的编写,会为你展现各种各样的编程任务。如果你不明白某些内容也不要担心,这个案例中的一些细节稍后会在本文档的后续部分一一解释。
注意! 为了达到更好的效果,请在Xcode里用playgound打开,因为它会编辑文章中列举的代码,还可以立即查看结果。
用let定义常量,var定义变量。在编译的时候程序不需要知道常量的值,但是你必须一次性给它赋予正确的值(一次赋值,到处引用。哪个语言的特性?),这意味着你可以用常量一次性定义一个值,但是可以在许多地方使用。
var myVariable = 42 myVariable = 50 let myConstant = 42
一个常量或者变量必须有相同的类型来表示你想去定义的的值,通常你并不需要显示的指示值的类型。显示指示的目的是为了在程序编译时让编译器知道你所定义的值的类型。如上面的例子所示,myVariable你定义的是一个整型类型,所以你需要显示的指示该类型为Integer。
如果你在初始化该值的时候没有提供足够的信息(或者你没有初始化),特殊的类型指定,需要用冒号+类型的形式指定。
let implicitInteger = 70 let implicitDouble = 70.0 let explicitDouble: Double = 70
如果定义个Float类型呢:
let explicitFloat:Float = 4
let label = "The width is " let width = 94 let widthLabel = label + String(width)
可以试试把上面最后一行的String去掉,看会出现什么错
let apples = 3 let oranges = 5 let appleSummary = "I have \(apples) apples." let fruitSummary = "I have \(apples + oranges) pieces of fruit."
练习 将float类型的值包含在字符串中 let impfloat1 = 0.5 let impfloat2 = 1.4 let appleSummary = "I have \(impfloat1) apples." let fruitSummary = "I have \(impfloat1 + impfloat2) pieces of fruit." (对不对?)
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>()
shoppingList = [] // Went shopping and bought everything. shoppingDic = [:]//我自己写的玩的。
let individualScores = [75, 43, 103, 87, 12] var teamScore = 0 for score in individualScores { if score > 50 { teamScore += 3 } else { teamScore += 1 } } teamScore
var optionalString: String? = "Hello" optionalString == nil var optionalName: String? = "John Appleseed" var greeting = "Hello!" if let name = optionalName { greeting = "Hello, \(name)" }
练习 如果把optionalName 变为nil.greeting的值是什么?添加一个else分句当optionalName为nil时设置不同的greeting(不会)
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." }
练习 如果删除default,会出什么错误
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
练习 添加一个变量跟踪哪一个kind的值是最大的,以及最大的number数是多少
var n = 2 while n < 100 { n = n * 2 } n var m = 2 do { m = m * 2 } while m < 100 m
var firstForLoop = 0 for i in 0..3 {//0,1,2 firstForLoop += i } firstForLoop var secondForLoop = 0 for var i = 0; i < 3; ++i { secondForLoop += 1 } secondForLoop
func greet(name: String, day: String) -> String { return "Hello \(name), today is \(day)." } greet("Bob", "Tuesday")
练习 删除today参数,添加一个参数,该参数要办好午餐特殊问候的。
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)
练习 写一个函数计算参数的平均数 <pre name="code" class="java">func average(numbers:Int...)->Double<pre name="code" class="java">var sum = 0var num = 0
sum += number num++}
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)
numbers.map({ (number: Int) -> Int in let result = 3 * number return result })
练习 重写组合体,当传入参数是奇数时,返回0
numbers.map({ number in 3 * number })
sort([1, 5, 3, 12, 2]) { $0 > $1 }
class Shape { var numberOfSides = 0 func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
练习 用let增加一个常量,并添加一个具有一个参数的方法 Class Shape{ let num = 1024 func simpleDes(name:String)->String{ return "A shape with \(name) sides" } }
var shape = Shape() shape.numberOfSides = 7 var shapeDescription = shape.simpleDescription()
class NamedShape { var numberOfSides: Int = 0 var name: String init(name: String) { self.name = name } func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } }
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()
练习 创建一个NamedShape的新的子类Circle。初始化时传入2个参数:name和radius.继承2个方法:area和describe。
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
如果你不需要计算属性的值,但是在设置新值的前后又需要提供一些代码,可以使用willSet和didSet方法。举例说明:下面的确定三角形的边长的类和边长的平方类似。
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
class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes times: Int) { count += amount * times } } var counter = Counter() counter.incrementBy(2, numberOfTimes: 7)
在处理可选值时(即该值可能为nil),你可以在处理类似于方法、属性、下表前添加问号(?),如果在问号(?)前是个nil值,问号(?)后的任何值都会被忽略而且整个表达式的值都为nil。另外,可选值会被跳过,而且问号(?)后所有的值都作为the unwrapped value(开关值)。在以上情况下,表达式的值为一个可选值。
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") let sideLength = optionalSquare?.sideLength(以上的解释可能是说,对于可选值来说,你要想获得其值,就需要先打开其值的开关,用!打开)
(有点C的感觉了哈)
用enum创建枚举类型,同类或者其他命名类型一样,枚举类型也可以含有与其相关的方法。
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()
练习 写一个函数通过比较2个Rank对象的原生值来比较他们
用toRaw和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()
练习 在Suit枚举中添加一个color方法,当spades和clubs返回"black"的值,当hearts和diamonds时返回"red"的值
当为hearts常量指定一个值时,枚举的成员变量Suit.Hearts会通过其全称而被引用,因为常量值没有一个显式的指定类型。而在Switch中,对Hearts的引用是通过简写形式.Hearts来引用的。因为self已经可以理解为一个Suit对象。所以在值的类型已知的任何场合,你都可以使用简写的方式。
用struct来创建结构体。结构体支持许多种形式,例如拥有方法和初始器的类。结构体和类最大的不同在于传递值的时候,结构体是直接复制,而类是引用。
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()
练习 在card中添加方法创造所有的扑克牌,每种级别和套装的组合出一张扑克
枚举类型中的每个成员的实例都可以拥有与实例相关的值。不同的枚举成员实例可以用不同的相关值。当你实例化时提供相关实例化值,相关值和原生值是不同的概念:一个枚举类型的成员的原生值对于所有实例都是一样的,而且当你定义枚举类型时你需要提供其原生值。
举例说明,考虑从服务器获取日出时间和日落时间,服务器会响应所请求的信息也可能返回错误信息。
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)" }
练习 在switch中增加第三种情况
注意如何从服务器ServerResponse 值中提取出匹配Switch条件的日出和日落时间。
用protocol定义协议
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
练习 写一个符合该协议的枚举类型
用extension给已知类型增加一个功能,比如新的方法和计算的属性。你也可以用一个extension为在任何地方声明的类型增加协议的一致性,甚至是一个从库或者框架中导入的一个类型增加这种扩展。
extension Int: ExampleProtocol { var simpleDescription: String { return "The number \(self)" } mutating func adjust() { self += 42 } } 7.simpleDescription
练习 为Double类型增加一个扩展,添加一个absoluteValue的属性。
let protocolValue: ExampleProtocol = a protocolValue.simpleDescription // protocolValue.anotherProperty // Uncomment to see the error
(又有了java的感觉)
在尖括号中写一个名称当做一个泛型的函数或者类型。
func repeat<ItemType>(item: ItemType, times: Int) -> ItemType[] { var result = ItemType[]() for i in 0..times { result += item } return result } repeat("knock", 4) http://write.blog.csdn.net/postedit/31371451
http://write.blog.csdn.net/postedit/31371451
你可以编写统一形式的函数和方法,就如同类、枚举、结构体。
// Reimplement the Swift standard library's optional type enum OptionalValue<T> { case None case Some(T) } var possibleInteger: OptionalValue<Int> = .None possibleInteger = .Some(100)
func anyCommonElements <T, U <strong>where</strong> 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])
练习 修改anyCommonElements函数,使得一个函数返回一个任何具有相同点的序列元素的数组
< T: Equatable>等同于
.
<T where T: Equatable>
.