swift 最基本的学习结束了,但是很多细节问题都没有搞的太明白,看以后的使用情况吧,在应用中再深入理解。明天就可以用swift开发项目了,高兴!
//: Playground - noun: a place where people can play import UIKit /*---------------------1.Swift的基本数据类型-----------------------------*/ var study = 0 if study < 100 { //1.1 Swift 关键字和标示符 //这样会报错 //var class = 2; var `class` = 2 //可以这样定义于标示符冲突的变量,但是不建议 /* 关键字分四类:声明相关的(private)语句相关的(break)类型表达式相关的(self)。特定上下文相关的(left,lazy)。 */ //变量的声明必须确定类型,可以自己显示的指定,也可以初始化让系统推断类型,下面都可以。 var b:Int var a = 10 var c :Int = 100 //也可以一次声明多个变量,类型也不需要相同 var d=20,e:Int,f="hello " //常量声明用的是let,其他部分声明方面和变量一样 let constA = 10 //constA =2 不能重新赋值 //数据输出 print(constA) print("a的值是:\(a),f的值是:\(f)")//用\(变量的)形式插入到字符串输出 //整形 /// 默认的Int长度等于所在平台的原生字长,细分了Int8,16,32和Uint8,Uint16,32等等 //var uchar :UInt8 = 256 //范围是0-255 超出范围 报错了 var unchar :UInt8 = 0128 //前面加0也可以 var binaryInt = 0b1001_0100 //可以用二进制表示,支持下划线分开 var hexInt = 0xAf var octalInt = 0o777 //这是八进制 //浮点数类型 1.十进制,2.科学技术法 5.2e3 = 5200 3.16进制数表示 0x5.a2p4,以0x开头,p代表4 //的p次方 = 0x5.a2 * 2^4 //浮点数提供了正无穷大,负无穷大和非数 三个 特殊的浮点数。 //正的浮点数 除以0.0得到正无穷,负的浮点数除以0.0得到负无穷,0.0除以0.0的非数 var float_a = 5.0,float_b = -5.0 print("正无穷和正无穷相等\(float_a/0.0==(4.0/0.0)),负无穷和负无穷相等\(float_b/0.0==(-4.0/0.0)),非数和非数自己都不相等\(0.0/0.0==(0.0/0.0))") //非浮点数除以0.0会报错的 //var int_num= 5 //int_num/0.0 // // // //数据类型的转换,数据类型转换如果数值超出范围就会报错,swift属于强类型语言,不同类型的值经常需要转换 var t_a:UInt8=100 var t_b:UInt16=10 //类型不一样,直接编译出错 //t_a=t_b; //t_b = t_a t_b = UInt16(t_a)//强制转换时可以的 //Bool值只能用true和false,不能用0或非0 表示,其他类型的值也不转化为bool值。在该使用bool值的地方一定要用Bool //这是不行的 //var i = 1 //if i //{ // // //} //var i = true //if i //{ // //这是可以的 //} // //元组 :tuple 使用圆花括号把多个值复合成一个复合值,定义元组类型的变量 var people = ("zhangsan",14,170.00) //这是系统推断的方式 var book :(String,Float,Int)//可以事先声明 book = ("bookname",30.0,2) print(book) var test : (Int,(Float,String))//元组成员又是元组 test = (10,(100.0,"bookName")) //元组访问 print(test.0)//可以通过点加下标的方式访问 print(test.1.0) //元组的拆分 var (num,(price,name))=test print("\(num),\(price),\(name)") let (c_num,(_,c_name))=test //可以用下划线表示要忽略元素 //可以使用key:value的形式为每个元组内的变量指明名字 var health = (height:175,weight:65)//可以直接写值 var score : (swift:Int,name:String)//也可以后面直接跟这个变量类型声明 score = (80,"real") //不写指定值只能按照格式顺序 score=(name:"real",swift:100)//指定值可以打乱顺序.所以访问元组的数据也可以通过元组的变量名访问 print(score.name) //可选类型 - var str_val = "123" var val1:Int? = Int(str_val) //.toInt这个方法找不到了,变成用构造器转换了不加?代码编译不过去,因为转换可能会失败。 //如果没有选择?,表示职能转换为Int,在转化失败的时候 属于『值缺失』,需要处理值缺失的时候即使nil //Switf里面 nil和OC的不同,OC里面的nil表示一个不存在对象的指针,Swift里面的nil表示的是确定的值,表示值缺失 //只有可选类型的变量或常量才能接受nil,非可选的变量和常量不可以接受,一个可选类型没有初始化,则值就是nil var option_a:String? = "1234" // 强制解析 :可选类型的变量和普通类型的变量不是相同的类型。比如不能直接把Int?直接转换为Int,用!表示 已知该变量有值,请提起其中的值 var value:Int = Int(option_a!)!//------需要这样写才能把可选类型的字符串转化为整数!!! var n1 :Int? = 100 var n2 :Int? = 50 let n3 = n1!+n2! print(n3) //强制解析必须是可选类型,并且里面确实有值才能成功,否则程序会出错,可以使用 if val!=nil 表示如果这个可选类型的变量不等于nil //可选绑定 :用于判断可选类型的变量和常量是否有值,如果可选的有值就赋值给另一个临时的变量或者常量 //可以在if分支对可选类型的变量进行判断 var str :String!="1234" if var tem = str//如果str的值为nil就不会去来这里了 { print(tem) } else { print("不能解析") } //隐式可选类型 //除了在任意已有类型的后面加?表示可选类型外,还可以在后面加!表示可选类型 //Int!和Int?区别是,当程序需要获取Int?类型的变量或常量值时候必须在变量后面添加!执行强制解析, //Int!不用 var aa :Int? = 100 var ab :Int! = 50 var cc :Int = aa! var dd :Int=ab //类型别名 //typealias 相当 typedef //typealias myInt = Int // 字符和字符串 //Character 表示单个字符 String 表示字符串,字符可以用单个字符,转义字符,"\u{n}"unicode编码表示 n表示 //1-8位16进制数 var chara:Character = "\u{2666}" print(chara) chara = "好" str = "两个不是图片的星星✨✨" //目前最新的swift countElement已经被改成了count print(str.characters.count) //插入字符串可以用字符串插值的方式 str = "前面插入了这些 \(str)" //for char in str //无法编译、 //{ // print(char) //} // var str_1 = "first✨
//var str_2 = "firsy" //print(str_1==str_2) //var hasPrefix:Bool = str_1.hasPrefix("first")//是否以特定的开头 //var hasSuffix:Bool = str_2.hasSuffix("sy") // ////访问字符串中的UNICODE码 print("这里是UTF8编码:能用UTF8表示的就显示一个数,不能用显示的就会输出多个,每个表示一个字节,分多个字节输出,星星用了226 156 168表示对") for codeUnit8 in str_1.utf8//这里返回的是一个utf8View类型的值,是一个包含多个Utf8的值的集合 { print(codeUnit8,terminator:" ")//现在改成这个了 不换行输出用这个语句 } print("这里是UTF16编码:和UTF8类似,这里每个表示一个字节") for codeUnit16 in str_1.utf16//这里返回的是一个utf8View类型的值,是一个包含多个Utf8的值的集合 { print(codeUnit16,terminator:" ")//现在改成这个了 不换行输出用这个语句 } ////这里一个表示4个字节 unicodeScalars返回的 UnicodeScalarView类型的值 包含一个或多个unicodeScalar的值 ////是一个21位的Unitcode码,需要用.value属性获得数值是一个 Uint 32 //for codeUnit32 in str_1.unicodeScalars//这里返回的是一个utf8View类型的值,是一个包含多个Utf8的值的集合 //{ // print(codeUnit32.value,terminator:" ")//现在改成这个了 不换行输出用这个语句 // //} } study++; //------------------------- 运算符 if study < 100 { //%求余数运算符 , 可以对小数求余数,两个操作数都是整数不能对0求余,有一个是浮点数,第二个可以是0.0或0结果是非数,余数的正负只和和除数的正负相关。 //var mod = 7.5%1.2 // //print(mod) // =0.3 //溢出运算符,如果希望程序只是对溢出的数据位进行截断,而不是导致错误,可以使用Swift提供的溢出预算符 //&(+ - * / %) //var a :UInt8 = 255 // //var b:UInt8 = 255+a //这样竟然可以 // //a = a &* 6 //溢出后进行截断操作 //范围运算符 a...b [a b] a..<b [a b) for var idx in 0...100 //(0..<100) { print(idx) } // 引用比较对象运算符 === 和 !==== 用来判断两个引用类型的变量是否指向同一个对象。, // == 用来比较内容 var d1 = NSMutableArray(); var d2 = NSMutableArray(); //d1 == d2 但是 d1!===d2 //nil 合并运算符 "a??b" 用来在可选类型的变量a是否为nil,如果为nil就返回后者b的值,a和b的类型必须一致 //相当于 a!=nil?a!:b } study++ ; if study < 100 { //var a=10 //if a>0 //{ // print(a)//即使这里只有一句 也必须用括号括起来 //} //switch不用加break,每一个switch必须包含一条语句 //不能这样 /** * case 1: case 2: print(); 但是可以这样 case 1,2: print(); 但是有的时候为了使用C语言里面的贯穿特性 可以使用fallthrough */ var num = 5; switch num { case 5...10: //可以表示范围 print(num) //fallthrough 加上这句话下面的就会执行 default: print(num+1) } var point:(x:Int,y:Int); point = (50,50) //(0,0)可以匹配到下面三个,遇到第一个就跳出,所以应该范围小的条件放在前面 switch point { // case (x:0,y:0): //(0,0) 也可以这样, // print("位于原点") // case (_,0)://元组里面可以匹配范围 // print("x轴>") // case (0,_): // print("位于Y轴") case (0...100,0..<100): print("在第一象限") //default : // break; // case (50,var y)://把元组的匹配的值放入变量y里面 // print(y); //case let d : //可以把switch的条件放到 变量或者常量中,如果希望在这里更改就用变量。这里let d 这语句可以匹配所有的情况所以可以替代default case var(x,y) where x > 0&&y>0: //在case里面可以进行再次筛选 print("第一象限--》") default: break; } //case的值 print(point) //循环结构 //var cnt = 10 //while cnt < 20 //{ // print(cnt) // cnt++ //} //do //{ // cnt++ //}while cnt<30 for idx in 0 ..< 3 //for循环 { print(idx) } for var a=0,b=0;a<0&&b<100;a++,b+=10//多个条件初始化 { print(a,b) } //for ;; 死循环 //{ // //} //for in 用于遍历字符串,范围,序列和集合等包含的元素 这里的常量无需声明 /** * for 常量名|_ in 字符串|范围|集合 */ var friend = "myfriend" for /*char*/_ in friend.characters //friend.characters 是最新的,原来只要写friend就行 { // print(char) print("kkk")//可以用 "_"来表示常量名,在不需要真正的遍历内容的时候可以用"_" } //这里的outer是一个标签,可以跳出到最外层的循环,有点类似于C语言的go语句,但是swift里面的标签只有放在循环 //开头出才有用,就像下面这样 outer:for i in 0 ..< 10 { inner: for j in 0 ..< 10 { print(i*j) if i*j==4 { break outer } if j==7 { continue//不会跳出循环 //continue outer 这里也可以跟一个标签。忽略标签所指定的循环中剩下的语句,默认是inner } } //continue outer发生后后这里的代码不会执行 } } // ----------------------------------- 4.集合 //var myArrs :Array<String>;//这里是声明,还不能用' // // //var myArr2:[Int] //这是构造器初始化 var myArr = Array<String>();//需要这样才能用 myArr.append("one") myArr+["two"] //可以这样 写加入元素 var myArr2 = Array<String>(count: 10,repeatedValue: "ones")//可以这样 //这里是简化语法初始化 var b = ("books",15); var values = ["a","b","c"] //访问数组的元素可以使用下标 print(values[0]) values.count//数组的个数 for element in values { print(element) } values .insert("d",atIndex: 0) //数组的可变性和可修改性完全取决于是用let还是var //数组的下标可以是范围 values[0...1] //多维数组 var secArr :[[Int]] //一个Int类型的二维数组 secArr = Array<Array<Int>>(count: 4,repeatedValue: [])//表示最外层的数组装了四个一维数组 secArr[0] = Array<Int>(count: 5,repeatedValue: 1) //----这样的循环过时了,不知道怎么写 for var i = 0,len = secArr.count;i<len;i += 1 { for var j = 0,len2 = secArr[i].count;j<len2;j += 1 { print(secArr[i][j])//遍历每个数组内的数组元素 } } // var n = 4 var drawArr = Array<Array<Int>>(count: n,repeatedValue: []);//声明一个二维数组 for i in 0 ..< n { drawArr[0] = Array<Int>(count: n,repeatedValue: 0) } drawArr[0].append(10) drawArr.removeLast(); var i = 0,j = 0,cur_pos = 1 var start = 0; drawArr[0] //-------字典 键和值用冒号隔开 var mydic:Dictionary=["key1":"value1","key2":"value2"] //声明语法 var scores:Dictionary<String,String> //这里是逗号, var scores2:[String:String] //这里是冒号: //泛型创建字典 var scores3:Dictionary<String,Int> scores3 = Dictionary(minimumCapacity: 5) //updateValue会返回一个字典内value的可选类型的值(?),如果原来的键值对不存在 //就返回nil scores3.updateValue(100,forKey: "math") scores3["chinese"]=90 scores3["english"]=80 for (item,score )in scores3// 前面是键后面对应的是值 { print(item,score) } var keys = Array(scores3.keys)//必须用Array构造器 scores3.count //字典的删除 scores3.removeAll(); //集合的复制,包含的数据是值类型复制副本,引用类型复制指针 var arr_ori = ["one","two","three"] var arr_cp1 = arr_ori; var arr_cp2 = arr_ori arr_cp1[0]+="1" arr_cp2[0]+="2" print(arr_cp1[0]) print(arr_cp2[0]) //引用复制 class User: NSObject { var name:String init(name:String) { self.name = name } } var UserOri = [User(name: "wokong"),User(name: "bajie")] var user1=UserOri; var use2=UserOri user1[0].name="oo" use2[0].name="d" ---- 5--------------------- 闭包和函数 study+=1; swift 不仅仅是面向对象的语言 /* func 函数名(形式参数列表)[->返回值类型] { } */ func max(x:Int,y:Int) -> Int { return x>y ? x:y } //支持多个返回值,需要元组的辅助 func getmessage(person:String) -> (String,String) { return ("test","100") } getmessage("mine") //也可以指定元组的返回参数 func getmessage2(person:String) -> (name:String,height:String) { return ("test","100") } var msg = getmessage2("test") print(msg.height,msg.name) //可以通过属性访问 //递归函数 func fn(i:Int) -> Int { if i==1 { return i } else { return i*fn(i-1); } } //fn(<#T##i: Int##Int#>) 这样只有数据类型不直观 print(fn(5)) //函数的形式参数 name和 msg都是参数 func sayHi(user name:String,msg:String) { print("程序正在执行sayHi()函数") print("\(name),\(msg)") } //sayHi(user: <#T##String#>,msg: <#T##String#>);// 指定参数名 //用局部形参名做形式参数名 ----- 这里是swift修改了 // //func sayHI2(#name:String) -> Void { // // //} //形参默认值,有默认值的话调用的时候可以省略形参,一般把带有默认值的放在后面。 func say2(user name:String="孙悟空") -> String { return name } print(say2()); //个数可变的形参,允许指定数量不确定的形参。在最有一个形参的类型后增加 ... 表示可以接受多个参数值,多个参数值被当成数组传入 func test(a :Int,books:String...) -> Void { for tmp in books { print(tmp) } } test(10,books: "OC","swift") //常量形参和变量形参,形参函数默认的是常量,在函数内不能对参数列表的形参进行修改,如果需要直接使用形式参数做变量,而不需要在函数内重新定义,需要用var //声明函数形参 //这里用var修饰已经提示过期了,就是参数就是不可修改的 func test2(/*var*/ width:Double,height:Double) -> Void { // width = 100; // 现在苹果不能用var修饰了 } // in out形参,用inout关键字声明的形参可以进行传递真实的值,不是副本,类似于 //C语言的传地址,这里是可以修改的 func test3(inout a:Int,inout b:Int) -> Void { a = a-b } //print(test3(&<#T##a: Int##Int#>,b: &<#T##Int#>)) 打出来就是这个样子的 var s_a = 3,s_b=4; test3(&s_a,b: &s_b) print(s_a) // 函数类型 --- C语言里面的函数指针 var p = test3; //可以直把函数赋值 var pType:(Int,Int)->Int pType = max; //函数类型做为参数 func fuc(a:Int,b:Int,p:(Int,Int)->Void) -> Void { p(a,b); } //函数重载,可以定义多个同名函数,但是要形式参数或者返回值不相同。 //函数的嵌套。默认的函数是全局的,嵌套在函数内的函数,在内部有效,可以通过 //前面的函数类型的返回值,返回具体的内容函数供外部调用 //----------------嵌套函数和闭包 ,闭包类似于Objective -C 里面的代码块 //-- 全局函数是一个有名称,但是不会捕获任何值的闭包。嵌套函数是一个有名字 //可以捕获封闭函数体的值的闭包,闭包表达式是一个简洁的,可以捕获封闭函数体的值的匿名闭包 //定义闭包 func getMathFunc(type:String) ->(Int)->Int { switch type { case "square": return{ (val:Int) ->Int in //闭包,放在一个大括号内,没有func关键字和函数名字 return val*val } case "cube": return{ (val:Int) -> Int in return val*val*val; } default: return { (val:Int) -> Int in var t = 0; for i in 0...100 { t+=i; } return val*t; } } } var mathFunc = getMathFunc("cube"); print(mathFunc(5)); //省略形参名。闭包表达式可省略,返回值的情况下,关键字 in也可以省略,闭包表达式可以通过$0,$1,$2来引用第一个,第二个。。。形参 //尾随闭包 //函数的参数类型是函数类型和闭包类型是相同的,可以传递闭包也可以传递函数 func someFunction (val:Int,fn:(Int)->(Int))->(Int) { //执行代码 return fn(val) } var sqare = { (val:Int)->Int in return val*val;//闭包只有一行代码,return 关键字 } print(someFunction(10,fn: sqare)) //这是普通闭包 someFunction(20,fn: {//放的是执行体 (val:Int)->Int in return val*val;//闭包只有一行代码,return 关键字 }) //这里是尾随闭包 someFunction(20)//闭包表达式在花括号的外面 { (val:Int)->Int in return val*val;//闭包只有一行代码,return 关键字 } //闭包捕获上下文的变量和常量,可以修改上下文中的常量和变量,即使定义这些变量和常量的作用域不存在了,也可以访问和修改???? func makeArray(ele:String)->()->[String] //返回的是一个没有参数,返回值为String的函数 { var arr:[String] = [] func addElement()->[String] { arr.append(ele) return arr } return addElement } //这注意 let add1 = makeArray("one") print(add1()) print(add1()) let add2 = makeArray("two") print(add2())//add2h额add1没有关系 //闭包是引用类型 var add3 = add2 //add3 直接更改值 print(add3()) //------ 面向对象上,除了定义自定义类还有枚举,结构,类。都支持定义存储属性,计算属性,方法,下标,高早起和嵌套类型 //------上面这句话暂时理解不了,信息量有点大呀。。。 说支持所有的类型。类,结构体,枚举这三种程序单元的内容分别可以定义属性(存储属性和计算属性),方法,下标,构造器和嵌套类型(嵌套类,嵌套结构体,嵌套枚举) //5种类型的成员,这5种成员在类,结构体,枚举各有区别 //-- 定义枚举 enum Season { case Spring // case 关键字 case Summer case Fall case Winter //case one,two 这样也是可以的 }// 这里没有给分配一个默认的整数值。枚举名就代表了一个实例。和整数没有任何关系 //定义了swift任意类型后,以下几方面使用 /* 1.声明变量 2.创建实例 3.访问类型属性 4.调用类型方法 5.派生子类 */ //声明变量 var sn :Season; sn = Season.Spring//可以直接用枚举的实例赋值 switch (sn) { case .Spring: print("spring") case .Summer: print("summer") default : print("default") } enum enum2:Int { case one,two=3,three //one = 0.three = 4 } enum enum3:Character { case one = "O" } //要么不指定,要么全部都必须确定有值,指定属性可以使用构造器的属性 var day = enum2.init(rawValue: 3);//根据值获取枚举值,可能失败的构造器 var day2 = day?.rawValue //枚举的关联值 //case 枚举值 (元组语法) enum Planet { case Earth(Double,String) case Mars(density:Double,name:String) case Sun } var p1 = Planet.Earth(1.0,"地球") var p2 = Planet.Mars(density: 2.0,name: "火星") switch(p2) { case Planet.Earth(var weight,var name): //真是奇葩,可以这样关联 print(weight,name) default: break; } //类和结构体 /* 区别: 1结构体不支持继承 2.不支持自定义构造器 3.结构体是指类型,不是引用类型 */ //swift的属性分为 存储属性(实例变量)和计算属性(相当于property合成的属性) //class表示一个属性或者方法是否属于类,static 用于结构体和枚举相当于类里面的class class person: NSObject { var name:String=""//必须初始化。 var age:Int=0 ; func say() -> Void { print("\(name) -- \(age)") } func say(message:String) -> Void {//函数 持重载 print("\(message)") } func growp(a:Int) -> person { age+=a return self } // init(n:String,a:Int) {//显示 定义带参数的构造器,没有自定义系统会提供一个默认的 // // self.age=a; // self.name=n // } } var per1 = person(); per1.name = "P1" per1.age = 0; per1.say() per1.say("消息") var per2 = person() per2.name="P1" per2.age=0; //===判断应用类型,==比较值类型,可以重载==号,自己定义比较类型 func ==(p1:person,p2:person) -> Bool { if p1.name==p2.name&&p1.age==p2.age { return true } return false } print(per2==per1) per1.growp(1).growp(2) //这里类似于OC里面的链式编程 //存储属性-- 存储在类,结构体,枚举内部的常量或者变量。 struct FixedLengthRange { var start:Int //定义常量存储属性 let length :Int //系统会为 "结构体" 提供所有存储属性的构造器,所以可以不指定初始值 } var rg = FixedLengthRange(start: 2,length: 3); //rg.length=0 初始化后就不能改 class lazyC: NSObject { lazy var tem = 100//懒加载关键在,类似于OC里面的重写get方法里面初始化,通过.语法访问才初始化 } //计算属性 property属性,实例计算属性和类计算属性 enum XBSeanon :Int{ case Spring,Summer,Fall,Winter //info就是计算属性 var info:String{ //在这里写get和set方法 get{ switch self { //去掉get方法就是只读属性 case .Spring: return "春" default: return "非春天" } } set(newValue)//这个形参可以省略, { if newValue=="春天" { self = .Spring } else { self = .Summer//瞎写测试 } } } mutating func changeV() //mutatiing 表示可变,用在结构体和枚举 { self = XBSeanon(rawValue: (self.rawValue+1)%3)! } } //var mys = XBSeanon.Spring //print("\(mys.info)")//get //mys.info = "春天" ////属性观察者。类似于KVO或者重写set方法实现的功能 class User { //这里的属性观察没有什么意义,因为没有重写setter方法和getter方法,对属性赋值操作检查应该在set方法做检查, var name :String = "" {//不能监听懒加载的熟悉 willSet{ //这里放的是属性赋值前,自动要执行的代码 if newValue.characters.count<3 { print("小于3") } } didSet { print("已经设置成功了") } /* get { return "success" } set { self.name = "fail" set和get代码和上面的不能共存,set个get要求没初始化,willSet和didSet应 } }*/ } func move(x:Int) { } } var U = User() U.name="1" U.name //属性和方法统一 //可以直接函数类型定义存储属性,并将函数和闭包传递就行 //下标 struct FKRect { var x:Int var y:Int var width:Int var heigth:Int subscript (idx:Int) ->Int //输入参数不支持指定外部参数,返回值可以返回任意类型,数组就是下标,字典就是value的类型 { get{ //定义一段可执行的代码, switch(idx) { case 0: return self.x case 1: return self.y case 2: return self.width; case _ : return self.heigth } } set { switch (idx) { case 0: self.width = newValue default: self.heigth = newValue } } } //int 是访问的形式,可以是字符串,联想字典 dict[@"one"]; subscript (idx:Int) -> String //输入参数不支持指定外部参数,返回值可以返回任意类型,数组就是下标,字典就是value的类型 { get{ //定义一段可执行的代码, switch(idx) { case 0: return "width" case 1: return "height" case 2: return "x" case _ : return "y" } } set { switch (idx) { case 0: self.width = 12 default: self.heigth = 123 } } } } var rect = FKRect(x: 0,y: 0,width: 100,heigth: 100) rect[0]=100 //通过下标引用 var num:String = rect[0] print(rect.width) //--------------------------可选择链 //可选链代替强制解析 class BOOK { var bookName:String! init(name:String) { self.bookName = name } } class Student { var book:BOOK! } class School { var stu:Student! } var school = School() //print(school.stu.book)// 这样写就错了。可以把!换成?作为可选链。!表示隐式解析,?表示可选链。中间有一个为nil就会返回nil,不会继续向后执行。 print(school.stu?.book) //可选链 适用于 属性,方法,下标 //-----类属性和类方法 (枚举,类,结构体自身的方法) //--值的类型属性包含枚举和结构体,用static修饰,包含存储属性和计算属性。“”“”类的类型属性只能定义计算属性“”“”“”“ //构造器---无须显示的声明返回值类型,无须显示的使用return返回实例,名字都是init函数,可以有多个函数重载 /** * 对于结构体提供两个构造器,无参数的和初始化所有的。对于类提供了无参数的。需要自定义的时候就自定义,自定义后就不在提供默认的 构造器的外部参数和局部参数相同--swift做的。 */ class TestInit { var name:String? let const = 10 // // init(_ n:String) // { // self.name = n // //self.const = 100//这里是不能被修改的。据课本上说原来是可以的 // } //构造器也可以重载 //可能失败的构造器, init?(_ n:String)//可能失败的构造器 { if n.characters.count<1 { return nil } } } //var testI = TestInit.init(n: "a") var testII = TestInit.init("A")//隐藏外部参数名字 //可能失败的构造器传播:可能失败的构造器可以调用同一个类中的普通构造器,普通构造器不能调用同一个类中可能失败的构造器,但是在结构体中普通的可以调用可能失败的。 class M1 :TestInit{ var grade:Int! init!(name:String,grade:Int) { super.init(name)//可能失败的调用 正常的 } } class M2 :M1{ var grade2:Int! // override init(name:String,grade:Int) //普通的不能调用可能失败的。 // { // // super.init?(name: name,grade: grade)//可能失败的调用 正常的 // } } //------------------------------------- 面向对象下 //********重写父类的属性,下标,观察者貌似全部更改了********/ //子类重写父类的属性 class brid { static var speed:Double = 0 } // ----- 变了---- //var eagle:brid //{ // var speed:Double{//重写父类的属性 //现在改了,不能这样写了。只能 // // get{ // print("正在访问被重写的属性") // } // set{ // super.speed = 100 // } // } //} //var eagle:brid //{ // var speed:Double{//重写父类的属性 //现在改了,不能这样写了。只能 // get{ // print("正在访问被重写的属性") // } // set{ // super.speed = 100 // } // } //} //--final 可以修饰类,属性,方法和下标,防止被集成,重写, final class Base { final var name :String="" final func say (content:String) { print("Base对象说\(content)") } } //类的构造和析构 class Apple { var name:String! var weight:Double init(name:String,weight:Double)//制定构造器,1个或者多个,完成所有的属性初始化,可以调用父类的制定构造器,如果有父类,必须调用父类的init { self.name = name; self.weight = weight } convenience init(n:String)//便利构造器 { self.init(name:n,weight: 100)//必须调用其他构造器 ,或者最终调用的是指定构造器 self.name = "xiugaile " } } //多态 class baseClass { func test() { print("基类的方法") } } class subClass:baseClass { override func test() { print("这是子类") } } class subClass2:baseClass { override func test() { print("这是子类2") } enum type { case height,low } } var instant:baseClass = subClass(); instant.test();//这里执行的其实是子类 //is运算符检验类型 相当于 isKindOf isMemberOf print("\(instant is subClass)") //as运算符向下转型 var instant2 = instant as? subClass2//类型强制转换,可能失败 //两个不确定的类型特殊类型 var arr:[Any] = ["one",1] //any表示任意类型,anyobject表示任意对象 // -- 扩展 extension String { //扩展方法 func XBLength(Str:String) ->Int { return Str.characters.count; } } // -- 协议 @objc protocol Draw //可选类型要有objc符号 { @objc optional var drawCirle:Double{get set};//属性 func drawCubic(width:Double);//方法 } class SwitftDraw:Draw { @objc var drawCirle:Double { get{ return self.drawCirle; } set { self.drawCirle = newValue; } } @objc func drawCubic(width: Double) { print("立方体 \(width)") } } //泛型 类型占位符 func copyArray <T> (src:[T],inout dest:[T]) { for element in src { dest.append(element) } } //这个方法可以复制任意类型的数组 //可以定义多个不同的参数 func projection<SrcType,DesType>(src :[SrcType],fn:(SrcType)->DesType) ->[DesType] { var result = [DesType](); for element in src { result.append(fn(element)); } return result; } var books = ["C和指针","算法导论"] var proj = projection(books){ $0.characters.count } //类也可以使用泛型 class AppleS<T:Comparable>//这里通过协议对泛型进行限定 { var info:T init(info:T) { self.info = info } } extension AppleS { //扩展类可以直接使用泛型 func bigThan(other:AppleS,fn:(T,T) ->Int) ->Bool { if fn(self.info,other.info)>0 { return true; } else { return false; } } }