创建对象
OC:alloc initWith
Swift:(XXX:)
调用方法
OC:[uicolor redcolor]
Swift:uicolor.redcolor()
枚举
OC:UIButtonTypeContactAdd
Swift:UIButtonType.ContactAdd
输出
OC:NSLog(@"Hello, World!");
Swift:2.0开始: print("Hello, World!")
注释
* Swift的编译器将会在编译代码时自动忽略掉注释部分
*单行注释//
*多行注释/**/
与C语言多行注释不同,Swift的多行注释可以嵌套在其它的多行注释之中嵌套多行注释
*注释嵌套/*/**/*/
常量变量
* let常量:常量的值一旦设定就不能改变
* var变量:变量的值可以随意更改
*常量&变量的使用原则:
*为保证数据的安全性尽量先用let,只有需要改变的时候才使用var
常量定义格式
*声明符号常量名称:类型标注
* let number: Int
*特点:一旦设定就不能改变
定义变量格式
*声明符号常量名称:类型标注
* var number: Int
*特点:变量的值可以随意更改
*注意:一般来说你很少需要写类型标注。如果你在声明常量或者变量的时候赋了一个初始值,Swift可以推断出这个常量或者变量的类型
常量和变量的命名
*你可以用任何你喜欢的字符作为常量和变量名,包括Unicode字符
*常量与变量名不能包含数学符号,箭头,保留的(或者非法的)Unicode码位,连线与制表符
*也不能以数字开头,但是可以在常量与变量名的其他地方包含数字
* ...和C和OC一样, no zuo no die
注意:
*如果你需要使用与Swift保留关键字相同的名称作为常量或者变量名,你可以使用反引号(`)将关键字包围的方式将其作为名字使用。
*无论如何,你应当避免使用关键字作为常量或变量名,除非你别无选择。
let🐶= "狗"
let `int` = 88
类型推断
*编译器可以在编译代码的时候自动推断出表达式的类型。(其它语言是没有类型推断)
*原理很简单,只要检查你赋的值即可
*如果没有指定表达式的类型,也没有赋予初始值,编译器会报错(type annotation missing in pattern)
//:指定类型
let dValue: Double
dValue = 22.2
print(dValue)
//:不指定类型,利用类型推断
let num = 10
print(num)
let value = 10.10
print(value)
元祖
*元组(tuples)把多个值组合成一个复合值
*将多个相同或者不同类型的值用一个小括号括起来就是一个元祖
*元组内的值可以是任意类型,并不要求是相同类型
*作为函数返回值时,元组非常有用
注意:
*元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组
//定义元祖
let student = ("lnj", 30, 99.8)
//通过下标来访问元组中的单个元素
print(student)
print(student.0)
print(student.1)
print(student.2)
//给单个元素命名
let student1 = (name:"lnj",age:30,score:99.8)
print(student1.name)
print(student1.age)
print(student1.score)
//元组的内容分解(decompose)
let (name , age , score) = ("lnj", 30, 99.8)
print(name)
print(age)
print(score)
类型安全
* Swift是一个类型安全(type safe)的语言,它会在编译你的代码时进行类型检查(type checks),并把不匹配的类型标记为错误。这可以让你在开发的时候尽早发现并修复错误
* swift对数据类型要求异常严格, swift中任何时候,都不会做`隐式转换`,如果要对不同类型的数据进行计算,必须显示类型转换
注意:
*结合数字类常量和变量不同于结合数字类字面量。字面量8可以直接和字面量3.1415926相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测
* Double和CGFloat也需要转换
let ii = 10
let jj = 10.1
//let sum = ii + jj //错误写法
let sum = Double(ii) + jj
print(sum)
//注意:Double()并不会修改intValue的值,而是通过intValue的值生成一个临时的值赋值给doubleValue
print(ii)
// Double和CGFloat也需要转换
let size = CGSize(width: 10, height: 10)
let res = size.width + CGFloat(dValue)
流程控制结构
Swift提供了类似C语言的流程控制结构(if/switch/for/while/dowhile)
分支if
*只能以Bool作为条件语句
*条件语句不需要加()
* {}不能省略
* Swift中if分支的模式可以使用where语句来判断额外的条件
*其它和OCif一样
let intValue = 10
if intValue > 5{
print("OK")
}
let testValue: Int? = 10
if let d = testValue where testValue > 9
{
print("满足")
}
Bool类型
* C语言和OC并没有真正的Bool类型
* OC语言的Bool类型YES/NO是`typedef signed char BOOL;`非0即真
Swift引入了真正的Bool类型true/false
* Swift中没有C和OC中非零即真的概念
* Swfit中逻辑值只有两个true/false
*如果你在需要使用Bool类型的地方使用了非布尔值,Swift的类型安全机制会报错
//if intValue = 10 { //可能将判断写错, Swift有效的避免了这种情况
if intValue == 10 {
print(intValue)
}
三目运算符
*三目运算符的特殊在于它是有三个操作数的运算符,它简洁地表达根据问题成立与否作出二选一的操作
*格式:问题?答案1 :答案2
提示:
* Swift中三目运算符用得很多
注意:
*过度使用三目运算符会使简洁的代码变的难懂。我们应避免在一个组合语句中使用多个三目运算符
let result = intValue > 20 ? 20 : 10
分支Switch
* OC中case后面必须加上break否则会贯穿, Swift不用
* Swift中如果想贯穿必须使用fallthrough
* OC中可以不写default,Swift中只有满足所有条件才能忽略default
* OC中default位置可以随便放,Swift不可以
* OC中在case中定义变量需要加大括号,否则作用域混乱, Swift不用加大括号
* Swift中的switch可以判断区间和元祖
* Swift中case分支的模式可以使用where语句来判断额外的条件
注意:
Swift中每一个case分支都必须包含至少一条语句,不像C语言里的switch语句,在Swift中,switch语句不会同时匹配多个条件
var rank = "A"
switch rank{
//default:
// print("没有评级")
case "A", "B":
var num = 10
print("优")
fallthrough
case "C":
print("差")
default:
print("没有评级")
}
匹配区间
*闭区间操作符...包含头包含尾
*半开区间操作符..<包含头不包含尾
var age1 = 10
switch age1 {
case 0:
print("0")
case 1..<18:
print("未成年")
case 18..<30:
print("成年")
default:
print("老年人")
}
//:匹配元祖
var point = (50, 50)
switch point{
//只有where后面的条件表达式为真才赋值并执行case后的语句
case (0, 0):
print("原点")
case (50, 50):
print("中点")
default:
print("Other")
}
//:值绑定(Value Bindings)
switch point{
//只有where后面的条件表达式为真才赋值并执行case后的语句
case var(x, y) where x > y:
print("\(x) > \(y)")
case var(x, y) where x < y:
print("\(x) < \(y)")
default:
print("Other")
}
可选类型
*可选类型表示变量可以有值,也可以没有值
* C和Objective-C中并没有可选类型这个概念
* Swift中只有可选类型才可以赋值为nil
*如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为nil
*格式: Optional<类型>或在类型后面加上?号
可选类型的取值是一个枚举
* None没有值
* Some有值
*由于可选类型在Swift中随处可见,所以系统做了一个语法糖,在类型后面加上?
注意:
* nil不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。
* Swift的nil和Objective-C中的nil并不一样。在Objective-C中,nil是一个指向不存在对象的指针,所以Objective-C只有对象类型才能被设置为nil(基本类型不行)。在Swift中,nil不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设置为nil,不只是对象类型。
var doubleValue1: Optional = 10.10
var intValue1: Int? = 0
intValue1 = nil
强制解析(forced unwrapping)
let url = NSURL(string: "http://www.520it.com/")
//如果强制解析OptionalValue,但是OptionalValue中没有值时会引发一个运行时错误
print(url!)
//需要考虑url是否有值
if url != nil{
let request = NSURLRequest(URL: url!)
}
可选绑定(optional binding)
*不需要考虑url是否有值,能进入{}一定有值
*不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值赋给一个常量或者变量
*可选绑定可以用在if和while语句中
提示:
*在实际开发中,使用频率很高
if let url3 = NSURL(string: "http://www.520it.com/"){
let request = NSURLRequest(URL: url3)
}
隐式解析可选类型(implicitly unwrapped optionals)
*有时候在程序架构中,第一次被赋值之后,可以确定一个可选类型_总会_有值。在这种情况下,每次都要判断和解析可选值是非常低效的,因为可以确定它总会有值
*隐式解析可选类型,并不需要每次都使用解析来获取可选值,一个隐式解析可选类型其实就是一个普通类型,但是可以被当做非可选类型来使用
*格式:将可选类型后面的?改为!
* let xmgButton: UIButton!
注意:
*如果一个变量之后可能变成nil的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否是nil的话,请使用普通可选类型
let url3: NSURL? = NSURL(string: "http://www.520it.com/")
let url4: NSURL! = NSURL(string: "http://www.520it.com/")
print(url3!) //需要惊叹号来获取值
print(url4) //不需要感叹号
循环
for循环-传统
* for后的圆括号可以省略
*只能以bool作为条件语句
*如果只有条指令for后面的大括号`不可以`省略
* for后面的三个参数都可以省略,如果省略循环保持语句,那么默认为真
for var i = 0; i < 10; i += 1
{
print(i)
}
for循环-Swift
*闭区间:包含区间内所有值a...b例如: 1...5
*半闭区间:包含头不包含尾a..
// 0~9之间
for i in 0..<10
{
print(i)
}
// 0~10
for i in 0...10
{
print(i)
}
忽略_
*不关心下标可以使用_忽略下标
*在Swift中_使用非常广泛
for _ in 0...10
{
print("lnj")
}
while循环
//: while循环,每次在循环开始时计算条件是否符合
var n = 0
while n < 10
{
print(n)
n += 1
}
//: repeat-while,每次在循环结束时计算条件是否符合
var m = 0
repeat{
print(m)
m += 1
}while m < 10
数组(有序数据集)
* Swift的Array类型被桥接到Foundation的NSArray类。
*格式: [] / [Int]() / Array()
* let不可变数组
* var可变数组
注意:
*不需要改变集合的时候创建不可变集合是很好的实践。如此Swift编译器可以优化我们创建的集合。
//创建一个空数组
var arrayM5: [String] = []
var arrayM4 = [String]()
var arrayM6 = Array()
//创建一个带有默认值的数组
let array1 = ["lnj", "lmj"]
let array2 = Array(count: 5, repeatedValue: 0)
//遍历
for item in array1{
print(item)
}
//遍历同时拿到索引
for (index, item) in array1.enumerate()
{
print("index = \(index), item \(item)")
}
//获取元素
array1[0]
array1[1]
//添加元素
//不能像不可变数组中添加内容
//array1.append("why")
// let不可变对象, var可变对象
var arrayM = ["lnj", "lmj"]
arrayM.append("why")
//数组可以存放任意类型
var arrayM2 = ["lnj", "lmj", 123]
arrayM2.append("456")
//如果需要添加其它类型必须提前声明为AnyObject
//arrayM.append(123)
//合并数组
var arrayM3 = ["zs", "ls", "ww", "zl"]
arrayM += arrayM3
//只有相同类型的数组才可以合并
//arrayM2 += arrayM3
print(arrayM.count)
//和区间搭配使用
arrayM += arrayM3[0...2]
print(arrayM.count)
//删除
arrayM3.removeAtIndex(1)
arrayM3
//删除所有
//arrayM3.removeAll()
//和区间搭配使用
//arrayM3.removeRange(Range(start: 0, end: 2))
arrayM3.removeRange(0..<2) //其实Range就是半闭区间
arrayM3
//删除并保留容量
arrayM3.removeAll(keepCapacity: true)
arrayM3.capacity
arrayM3.append("1")
arrayM3.capacity
arrayM3.append("2")
arrayM3.capacity
arrayM3.append("3")
arrayM3.capacity
arrayM3.append("4")
arrayM3.capacity
arrayM3.append("5")
//超过容量,容量会直接*2
arrayM3.capacity
字典(无序数据集)
* Swift的Dictionary类型被桥接到Foundation的NSDictionary类。
*格式[:] / Dictionary
* let不可变字典
* var可变字典
注意:
*一个字典的Key类型必须遵循Hashable协议
//创建一个空字典
var dict3: [String: AnyObject]
dict3 = [:]
var dict4 = [String: AnyObject]()
//创建一个带有默认值字典
var dict5 = ["name": "lnj", "age": 30]
//最常见的字典类型[String : AnyObject],例如JSON
var dict = ["name":"lnj", "age": 30]
//遍历字典
// k,v可以随便写,前面是key后面是value
for (k, v) in dict{
print(k)
print(v)
}
//获取元素
dict["name"]
//添加元素
//如果key不存在会新增
dict["gender"] = "man"
dict
//替换元素
//如果key存在会替换
dict["name"] = "why"
//删除元素
dict.removeValueForKey("name")
dict
//合并字典
var dict2 = ["score": 123]
for (k, v) in dict2{
dict[k] = v
}
dict
字符串
* Swift的String类型与Foundation NSString类进行了无缝桥接
* OC语言中的字符串也是以\0结尾, Swift不是
* OC中字符串是一个对象, Swift中使用String是一个结构体,效率更高,支持遍历
注意
* Swift的String类型是值类型。如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作
// Swift字符串不是以\0结尾
var stringValue = "abc\0bcd"
print(stringValue)
//遍历字符串
var str = "南哥很帅"
for c in str.characters
{
print(c)
}
//连接字符串和字符
var str2 = "cool"
str2 += str
let myAge:Int? = 30
let myName = "lnj"
//字符串插值
//拼接字符串的时如果字符串是可选内心,要特别注意,会带上Optional
let str3 = "name = \(myName), age = \(myAge!)"
//需要格式的时候,怎么办00:00:00
let frmStr = String(format: "%02d:%02d:%02d", arguments: [9, 23, 8])
//字符串截取,建议使用NSString
let str4 = "xmgcool"
let nsStr: NSString = str4
let subStr = nsStr.substringWithRange(NSMakeRange(0, 3))
//使用startIndex属性可以获取一个String的第一个Character的索引
//使用endIndex属性可以获取最后一个Character的后一个位置的索引
let subStr2 = str4.substringToIndex(str4.startIndex.advancedBy(3))
let range = Range(start: str4.startIndex, end: str4.startIndex.advancedBy(3))
let subStr3 = str4.substringWithRange(range)
函数:
*函数是用来完成特定任务的独立的代码块。你给一个函数起一个合适的名字,用来标识函数做什么,并且当函数需要执行的时候,这个名字会被用于“调用”函数
*格式:
* func函数名称(参数名:参数类型,参数名:参数类型...) ->函数返回值{函数实现部分}
没有参数没有返回值
1.可以写为->Void
2.可以写为->()
3.可以省略
* Void。它其实是一个空的元组(tuple),没有任何元素,可以写成()
func say() -> Void{
print("lnj")
}
say()
func say2() -> (){
print("lnj")
}
say2()
func say3(){
print("lnj")
}
say3()
有参数没有返回值
内部/外部参数
*内部参数: Swift2.0以前,默认情况下的参数都是内部参数
* Swift2.0开始,默认将第二个参数名称作为外部参数
*外部参数只能外部用,函数内部不能使用,函数内部只能使用内部参数
*忽略外部参数:在内部参数前加_
func sum(a: Int, b: Int){
print(a + b)
}
sum(10, b: 20)
func summ(a: Int, _ b: Int){
print(a + b)
}
summ(10, 20)
// xy外部参数, ab内部参数
// Swift2.0以前可以写#
func sum2(x a: Int, y b: Int){
print(a + b)
}
sum2(x: 10, y: 20)
默认参数(Default Parameter Values)
*格式: func method(parameter: Int = 0){}
*当默认值被定义后,调用这个函数时可以忽略这个参数
*其它语言的默认参数必须写在最后面, Swift可以写在任意位置
注意
*将带有默认值的参数放在函数参数列表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。
func joinString(s1:String , jioner:String = "❤️",toString s2:String) ->String
{
return s1 + jioner + s2;
}
joinString("lnj", jioner: "和", toString: "xmg")
joinString("lnj", toString: "xmg")
常量参数和变量参数(Constant and Variable Parameters)
*函数参数默认是常量,在函数内部不能修改
*如果想在函数中修改参数,必须在参数前加上var
注意
*对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中
func swap(var a:Int, var b:Int)
{
print("交换前a = \(a) b = \(b)")
let temp = a;
a = b; //可以修改,但不会影响实参
b = temp;
print("交换后a = \(a) b = \(b)")
}
var x = 10
var y = 20
print("交换前a = \(x) b = \(y)")
swap(x, b: y)
print("交换后a = \(x) b = \(y)")
输入输出参数(In-Out Parameters)
*变量参数,正如上面所述,仅仅能在函数体内被更改。如果你想要一个函数可以修改参数的值,并且想要在这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters)
*定义一个输入输出参数时,在参数定义前加inout关键字
注意
*输入输出参数不能有默认值,而且可变参数不能用inout标记。如果你用inout标记一个参数,这个参数不能被var或者let标记。
func swap2(inout a:Int, inout b:Int)
{
let temp = a;
a = b;
b = temp;
}
var x1 = 10;
var y1 = 20;
print("交换前a = \(x1) b = \(y1)")
swap2(&x1, b: &y1)
print("交换后a = \(x1) b = \(y1)")
可变参数(Variadic Parameters)
*一个可变参数可以接收零个或多个值
*如果没有变参函数,并且函数的参数个数又不确定那么只能写多个方法或者用将函数参数改为集合
*格式func method(parameter: Int...){}
*可变参数在函数中可以当做一个数组
注意
*一个函数最多只能有一个可变参数
*变参只能是同种类型的数据
*变参必须指定数据类型
*如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后
func add(nums:Int..., other:Int) -> Int
{
var sum = 0;
for num in nums
{
sum += num
}
return sum + other
}
print(add(1, 2, 3, other: 9))//会将99传递给第一个参数,后面的传递给nums
//没有参数有返回值
func getNumer() ->Int{
return 998
}
print(getNumer())
//有参数有返回值
func sum3(a: Int, b: Int) ->Int{
return a + b
}
print(sum3(10, b: 20))
//嵌套函数
func showArray(array:[Int])
{
//嵌套函数
func printArray(arr:[Int])
{
for number in array
{
print("\(number), ")
}
}
printArray(array)
}
showArray([1, 3, 5, 7, 9])
函数类型(Function Types)
*函数类型作为参数类型(Function Types as Parameter Types)
*函数类型作为返回类型(Function Types as Return Types)
*嵌套函数(Nested Functions)
提前退出
*像if语句一样,guard的执行取决于一个表达式的布尔值。我们可以使用guard语句来要求条件必须为真时,以执行guard语句后的代码。
*如果guard语句的条件被满足,则在保护语句的封闭大括号结束后继续执行代码
*任何使用了可选绑定作为条件的一部分并被分配了值的变量或常量对于剩下的保护语句出现的代码段是可用的
*如果条件不被满足,在else分支上的代码就会被执行。
* else这个分支必须转移控制以退出guard语句出现的代码段。它可以用控制转移语句如return,break,continue或者throw做这件事
func divide3(dividend: Double?, divisor: Double?) -> Double? {
guard let dividend = dividend else {
return .None
}
guard let divisor = divisor else {
return .None
}
guard divisor != 0 else {
return .None
}
return dividend / divisor
}
print(divide3(10, divisor: 20))