这是我自己开始学习swift3.0开始敲过的demo,只是粗略的过了一遍,如有问题,请指正谢谢
点击
下载demo
import Foundation print("Hello,World!") //用let做一个常数和var使一个变量。常量的值在编译时不需要知道,但您必须为其分配一次值。这意味着您可以使用常量来命名一次您确定的值,但在许多地方使用。 var myAge = 23 myAge = 60 let youAge = 30 let myPrice = 76.7 let youPrice: Double = 75.9 // 值不会隐式转换为另一种类型。如果需要将值转换为不同的类型,请显式地创建所需类型的实例。 let label = "this is width" let width = 50 let labelWidth = label + String(width) // 还有一个更简单的方法,包括在字符串值:写在括号中的数值,并写一个反斜杠(\括号之前)。例如: let apples = 5 let oranges = 6 let myApple = "I have apple is\(apples)" let myOranges = "I have oranges is\(oranges)" print(myApple) print(myOranges) //创建用括号(数组和字典[]),以及通过写在括号内的索引或关键访问其内容。最后一个元素之后允许逗号。 var shoppingList = ["cat","water","fish","mike","friut"] shoppingList[2] = "caonima"//给数组第三个参数赋值 var personDict = [ "age" : "12","sex" : "男",] personDict["hello"] = "tian tian xiang shang" //字典添加键值对 print("\(shoppingList)++++++\(personDict)") //要创建空数组或字典,请使用初始化语法。 let emptyArray = [String]() let emptyDict = [String : String]() //如果类型信息可以推断,你可以写一个空数组作为[]和一个空的字典作为[:]-例如,当你为一个变量设置一个新值或传递一个参数传递给函数。 shoppingList = [] personDict = [:] print("\(shoppingList)++++\n+\(personDict)") //使用if和switch制作条件语句,并使用for- ,,in 和- 进行循环。条件或循环变量的圆括号是可选的。身体周围的大括号是必需的。 forwhilerepeatwhile let classStudentscores = [89,90,56,78,90] var teamscore = 0 for score in classStudentscores{ if score > 80{ teamscore += 3 }else{ teamscore += 1 } } print("团队分数是:\(teamscore)") /* 在一个if语句,条件必须是布尔表达式,这意味着它们代码诸如if score { ... }是一个错误,而不是隐式比较为零。 您可以使用if,并let连同可能被遗漏值工作。这些值表示为可选。可选的值或者包含一个值,或包含nil以指示值丢失。写一个问号(?)值的类型之后,以纪念价值为可选。 **/ var optionString: String? = "hello" print("\(optionString)") print(optionString != nil)//输出的是true var optionalName :String? = "yutaotao very goog" var greeting = "hello!" if let name = optionalName { print("name is \(name)") } /* 如果可选的值nil,条件是false在括号中的代码被跳过。否则,该可选值是解开并分配给恒定之后let,这使得可用的代码块中的展开值。 处理可选值的另一种方法是提供一种使用一个默认值??运算符。如果缺少可选值,则使用默认值。 */ let nickName:String? = nil let fullName: String? = "full...." print("nickName is \(nickName) fullName is \(fullName)") //开关支持任何类型的数据和各种比较操作 - 它们不限于整数和相等的测试。 let vegetable = "resd pepper" switch vegetable { case "celery": print("Add some raisins and make ants on a log.") case "cucumber","watercress": print("That would make a good tea sandwich.") case let x where x.hasSuffix("per"): //asPrefix:和hasSuffix: 前缀和后缀 和 vegetable 比较 print("Is it a spicy \(x)?") default: print("Everything tastes good in soup.") } //您可以使用for- in通过提供一对名字的使用为每个键-值对迭代在字典中的项目。字典是一个无序的集合,所以它们的键和值以任意顺序迭代。 let interStringNumbers = [ "score" : [12,89,87,56],"age" : [15,1,43,31,66],"monery" : [1,2,3,4,5],] var largest = 0 for (kind,numbers) in interStringNumbers { for number in numbers { if(number > largest){ largest = number print("largest is \(largest)") } } } print("largest is ===== \(largest)") //使用while重复的代码块,直到病情变化。循环的条件可以是结束,确保循环至少运行一次。 var n = 2 while n < 65 { n = n*2 } print("n is \(n)") var m = 2 repeat { m = m * 2 }while m < 99 print("m is \(m)") //您可以通过使用保持在一个循环的索引..<,使一系列指标。 var total = 0 for i in 0..<4{//半闭区间运算符 ..<这里是0到3之间(这里不包括4),...为区间运算符这里使用的话是0到4之间 total += i print("total is \(total)") } print("total is =====\(total)") //函数和闭包 使用func声明函数。通过跟随它的名称和括号中的参数列表来调用函数。使用->的参数名称和类型从函数的返回类型分开。 func greet(person: String,day: String)->String{ return "helllo \(person),today is \(day)" } //默认情况下,函数使用它们的参数名称作为其参数的标签。参数名前编写自定义参数标签,或写_为不使用参数的标签。 func greets(on person: String,on day: String) -> String { return "Hello \(person),today is \(day)." } print("\(greets(on: "john",on: "wed"))") //使用元组制作复合值 - 例如,从函数返回多个值。元组的元素可以通过名称或通过数字来引用。 func getMaxMinSum(scores :[Int]) ->(min:Int,max:Int,sum:Int){ var min = scores[0] var max = scores[0] var sum = 0 for score in scores{ if score > max { max = score } else if score < min { min = score } sum += score } return(min,max,sum) } print(getMaxMinSum(scores: [12,34,51,9,33]).max); print(getMaxMinSum(scores: [12,33]).min); print(getMaxMinSum(scores: [12,33]).sum); //函数也可以采用可变数量的参数,将它们收集到数组中。 func getSum(scores:Int...)->Int{ var sum = 0 for score in scores { sum += score } return sum } print(getSum(scores: 12,23,44,61,23));//这里可以填无数个数字 //函数可以嵌套。嵌套函数可以访问在外部函数中声明的变量。您可以使用嵌套函数来组织长或复杂的函数中的代码。 func returnFifteen() -> String { var name = "taotao" func hello (){ print("hello,") } hello() print(name) return "\(name)" } print(returnFifteen()) //函数是一等类型。这意味着一个函数可以返回另一个函数作为它的值。 func makeIncrementer() -> ((Int) -> Int) { func addOne(number: Int) -> Int { return 1 + number } return addOne } var increment = makeIncrementer() print(increment(7)) //函数可以将另一个函数作为其参数之一。 func addAnyFoution(list:[Int],condition:(Int)->Bool)->Bool{ for item in list { if condition(item) { return true } } return false } func lessThanTen(number: Int)-> Bool { if number > 10 { return true } return false } var numbers = [12,45,55,77] print(addAnyFoution(list: numbers,condition: lessThanTen)) /* 函数实际上是闭包的特殊情况:稍后可以调用的代码块。闭包中的代码可以访问在创建闭包的范围中可用的变量和函数,即使闭包在执行时处于不同的范围 - 您已经使用嵌套函数看到了一个示例。你可以使用大括号({})来写一个没有名字的闭包。使用in分离的参数和从身体返回类型。*/ var res = numbers.map({ (number: Int)-> Int in let result = number * 3 return result }) print(res) //你有几个选项更简洁地写闭包。当一个闭包的类型已经知道,例如一个委托的回调,你可以忽略它的参数的类型,它的返回类型,或两者。单语句闭包隐式返回其唯一语句的值。 let mappperNumber = numbers.map({number in 3 * number}) print(mappperNumber) //您可以按数字而不是按名称引用参数 - 此方法在非常短的闭包中尤其有用。作为函数的最后一个参数传递的闭包可以紧跟在括号后面。当闭包是函数的唯一参数时,可以完全省略括号。 let sorteNumbers = numbers.sorted{$0 > $1}//排序闭包 print(sorteNumbers) /* 对象和类 使用class后面的类的名称来创建一个类。类中的属性声明的写法与常量或变量声明相同,除非它在类的上下文中。同样,方法和函数声明的写法也是一样的。*/ class shape { var numberOfsides = 0 func simpleDescription() -> String { return "类 shape with \(numberOfsides) sides" } } var shap = shape() shap.numberOfsides = 8 var shapeDescption = shap.simpleDescription() print(shapeDescption) //上面的个版本的Shape类缺少一些重要的东西:创建实例时设置类的初始化器。使用init创建一个。 class ameShape{ var numberOfsides:Int = 0 var name :String init(name: String) { self.name = name } func simpleDescption() -> String { return "\(name) shape with \(numberOfsides) sides" } } /** 注意如何self用来区分name属性和name参数到初始化器。初始化器的参数在创建类的实例时像一个函数调用一样传递。每个属性都需要一个赋值的值,无论是在声明中(如with numberOfSides)还是在初始化器中name。 deinit如果需要在释放对象之前执行一些清理, 请使用创建deinitializer。 子类在类名之后包括它们的超类名,用冒号分隔。不需要类来子类化任何标准根类,因此您可以根据需要包括或省略超类。 覆盖超类实现的子类上override的方法标记为 - 意外覆盖一个方法,而不会override被编译器检测为错误。编译器也检测方法override,并不实际覆盖超类中的任何方法。 */ class Square: ameShape { 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 simpleDescption() -> String { return "\(name) shape with \(sideLength) sides" } } let test = Square(sideLength: 5.2,name:"my name is taotao") print(test.area()) print(test.simpleDescption()) //除了存储的简单属性,属性可以有一个getter和一个setter。 class EquilateralTriangle: ameShape{ var sideLength: Double = 0.0 init(sideLength:Double,name:String) { self.sideLength = sideLength super.init(name: name) numberOfsides = 3 } var perimiter:Double{ get { return 3.0*sideLength } set{ sideLength = newValue / 3.0 } } override func simpleDescption() -> String { return "An equilateral triangle with sides of length \(sideLength)." } } var triangle = EquilateralTriangle(sideLength:3.1,name:"a triangle") print(triangle.perimiter) triangle.perimiter = 9.9 print(triangle.sideLength) /* 在setter for中perimeter,新值具有隐式名称newValue。您可以在后面的括号中提供显式名称set。 注意,EquilateralTriangle类的初始化器有三个不同的步骤: 设置子类声明的属性的值。 调用超类的初始化器。 更改由超类定义的属性的值。任何使用方法,getter或setter的额外设置工作也可以在这一点上完成。 如果您不需要计算属性,但仍需要提供在设置新值之前和之后运行的代码,请使用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") print(triangleAndSquare.square.sideLength) print(triangleAndSquare.triangle.sideLength) triangleAndSquare.square = Square(sideLength: 50,name: "larger square") print(triangleAndSquare.triangle.sideLength) /**使用可选值时,可以在操作?之前写入方法,属性和下标。如果前面的值?是nil,后面的所有内容?都被忽略,并且整个表达式的值是nil。否则,可选值将被展开,并且?对展开的值执行操作后的所有内容。在这两种情况下,整个表达式的值都是可选值。**/ let optionalSquare: Square? = Square(sideLength: 2.5,name: "optional square") let sideLength = optionalSquare?.sideLength /** 枚举和结构 使用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.rawValue) } } } let ace = Rank.ace let aceRawValue = ace.rawValue /* 默认情况下,Swift分配从零开始并每次递增一的原始值,但您可以通过显式指定值来更改此行为。在上面的例子中,Ace显式给出一个原始值1,其余的原始值按顺序分配。您还可以使用字符串或浮点数作为枚举的原始类型。使用该rawValue属性可访问枚举案例的原始值。 使用init?(rawValue:)初始化程序从原始值创建枚举的实例。 */ if let convertedRank = Rank(rawValue: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() print(heartsDescription) /*** 请注意hearts上面引用枚举的情况的两种方式:当向hearts常量分配值时,枚举大小写Suit.hearts以其全名引用,因为常量没有指定显式类型。在交换机内部,枚举情况由缩写形式引用,.hearts因为值self已知为诉讼。您可以在值的类型已知时随时使用缩写形式。 如果枚举具有原始值,则将这些值确定为声明的一部分,这意味着特定枚举案例的每个实例始终具有相同的原始值。枚举案例的另一个选择是具有与案例相关联的值 - 这些值是在创建实例时确定的,并且对于枚举案例的每个实例它们可以不同。您可以将相关联的值视为与枚举案例实例的存储属性类似。例如,考虑从服务器请求日出和日落时间的情况。服务器响应所请求的信息,或者响应以什么错误的描述。 */ enum ServerResponse { case result(String,String) case failure(String) } let success = ServerResponse.result("6:00 am","8:09 pm") let failure = ServerResponse.failure("Out of cheese.") switch success { case let .result(sunrise,sunset): print("Sunrise is at \(sunrise) and sunset is at \(sunset).") case let .failure(message): print("Failure... \(message)") } /** 注意如何从ServerResponse值中提取日出和日落时间,作为与开关情况匹配的值的一部分。 使用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() print(threeOfSpadesDescription) /* 协议和扩展 使用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 print("类使用协议\(aDescription)") struct SimpleStructure: ExampleProtocol { var simpleDescription: String = "A simple structure" mutating func adjust() { simpleDescription += " (adjusted)" } } var b = SimpleStructure() b.adjust() let bDescription = b.simpleDescription print("结构体使用协议\(bDescription)") /** 注意在声明中使用mutating关键字SimpleStructure来标记修改结构的方法。声明SimpleClass不需要标记为mutating的任何方法,因为类上的方法总是可以修改类。 用于extension向现有类型添加功能,例如新方法和计算属性。您可以使用扩展来为在其他位置声明的类型添加协议一致性,甚至可以将其添加到从库或框架中导入的类型。 **/ extension Int: ExampleProtocol { var simpleDescription: String { return "The number \(self)" } mutating func adjust() { self += 42 } } print(7.simpleDescription) /* 您可以像任何其他命名类型一样使用协议名称,例如,创建具有不同类型但都符合单个协议的对象的集合。使用类型为协议类型的值时,协议定义之外的方法不可用。 **/ let protocolValue: ExampleProtocol = a print(protocolValue.simpleDescription) // print(protocolValue.anotherProperty) // Uncomment to see the error /** 错误处理 您使用任何采用Error协议的类型表示错误。*/ enum PrinterError: Error { case outOfPaper case noToner case onFire } //使用throw抛出一个错误,并throws标记,可以抛出一个错误的功能。如果在函数中抛出错误,函数立即返回,调用函数的代码处理错误。 func send(job: Int,toPrinter printerName: String) throws -> String { if printerName == "Never Has Toner" { throw PrinterError.noToner } return "Job sent" } /** 有几种方法来处理错误。一种方法是使用do- catch。在do块内,你标记可以通过try在它前面写入错误的代码。在catch块内,错误会自动给定名称error,除非你给它一个不同的名称。*/ do { let printerResponse = try send(job: 1040,toPrinter: "Bi Sheng") print(printerResponse) } catch { print(error) } //您可以提供catch处理特定错误的多个块。你写一个模式,catch就像你case在交换机之后。 do { let printerResponse = try send(job: 1440,toPrinter: "Gutenberg") print(printerResponse) } catch PrinterError.onFire { print("I'll just put this over here,with the rest of the fire.") } catch let printerError as PrinterError { print("Printer error: \(printerError).") } catch { print(error) } //另一种处理错误的方法是使用try?将结果转换为可选。如果函数抛出错误,则丢弃特定错误,结果为nil。否则,结果是一个可选的,包含函数返回的值。 let printerSuccess = try? send(job: 1884,toPrinter: "Mergenthaler") let printerFailure = try? send(job: 1885,toPrinter: "Never Has Toner") /** 用defer写的是在函数中的所有其它代码后执行代码块,只是在函数返回之前。无论函数是否抛出错误,代码都会执行。您可以使用defer彼此相邻地写入设置和清除代码,即使它们需要在不同的时间执行。**/ var fridgeIsOpen = false let fridgeContent = ["milk","eggs","leftovers"] func fridgeContains(_ food: String) -> Bool { fridgeIsOpen = true defer { fridgeIsOpen = false } let result = fridgeContent.contains(food) return result } fridgeContains("banana") print(fridgeIsOpen) /** 泛型在尖括号中写一个名称以创建一个通用函数或类型。*/ func makeArray<Item>(repeating item: Item,numberOfTimes: Int) -> [Item] { var result = [Item]() for _ in 0..<numberOfTimes { result.append(item) } return result } makeArray(repeating: "knock",numberOfTimes:4) //您可以创建通用形式的函数和方法,以及类,枚举和结构。 // Reimplement the Swift standard library's optional type enum OptionalValue<Wrapped> { case none case some(Wrapped) } var possibleInteger: OptionalValue<Int> = .none possibleInteger = .some(100) //where在正文之前 使用right来指定需求列表 - 例如,要求类型实现协议,要求两种类型相同,或者要求类具有特定的超类。 func anyCommonElements<T: Sequence,U: Sequence>(_ lhs: T,_ rhs: U) -> Bool where T.Iterator.Element: Equatable,T.Iterator.Element == U.Iterator.Element { for lhsItem in lhs { for rhsItem in rhs { if lhsItem == rhsItem { return true } } } return false } anyCommonElements([1,3],[3])