Swift学习笔记
一、基础语法3.0
1.运算符
1.赋值运算法:=
a.不是数学中判断两边是否相等的等号,是讲“=”右边的值赋给左边的变量或者常量
b.等号右边可以是变量或者常量或者表达式
c.赋值表达式没有返回值(C有)
let a = 10 // 右边是值
let b = a // 右边是常量a
let c = b+10 // 右边是表达式大
2.求商: /
//数学中 10/2=5 11/2=5.5
//swift 10/2=5 11/2=5 11.0/2=5.5
//两个整数相除,商也是整数
除号两边的类型必须一致
let e1=11/2 //运行结果为5
let e3=e1/3 // 1
let e2=2.0
let e4=(Double)(e1)/e2 //e1为整型,e2为Double型,所以这里把e1转换也转换为Double型,结果为2.5
求余: %
10%3 // 1
10%5 // 0
15611153%1000 //这样可以求到个、十、百位上的数 ,结果为153
//求一个数百万位上的数字:4641531218
let h1 = 4641531218%10000000 //拿到百万位以后的所有数 1531218
let h2 = h1/1000000 就可以拿到百万位上的数了
三目运算符:?
格式:条件语句?表达式1:表达式2
要求:条件语句的结果必须是Bool值
功能:如果条件语句的结果是true,执行语句1,结果是false执行语句2
let money = 110
let price = 100
var str:String
(money>price) ? (str = "buy it"):(str = "Oh no,I can't afford it"
2.分支表达式
1. if语句
格式: if 条件语句{满足条件需要执行的代码}
功能:条件语句的结果必须为真才会执行{}里的语句,由此可判断条件语句是否为真
注意:if 后的条件语句不需要()等来修饰,而条件语句后执行语句的必须用{}
var score == 100
if score == 100{
print("迎娶白富美,担任CTO,走向人生巅峰")}
2.if-else
格式:if 条件语句{满足条件就执行此语句} else{不能满足条件语句就执行此语句}
功能:条件语句为真,执行语句1;为假,执行else里的语句
var score == 99
if score == 100{
print("迎娶白富美,担任CTO,走向人生巅峰")
}
else{
print("滚")
3.if语句的嵌套
手机电量:电量小于20 红色 20~40黄色 大于40绿色
方案1
var powerValue = arc4random_uniform(101) //0~100随机数
var powerViewColor:UIColor
if powerValue <= 20{
powerViewColor = UIColor.redColor() //电量小于等于20变红
}else{
if powerValue <= 40{
powerViewColor = UIColor.orangeColor() //20~40变成橘黄色
}else{
powerViewColor = UIColor.grennColor() //其余的(40~100)呈绿色
}
}
4.switch
格式: switch 表达式{ case 条件1: 语句1 case 条件2: 语句2 … default: 语句N }
功能:计算表达式的值,然后根据值和每个case后面的条件进行判断,符合哪个case后面的条件就执行该case后面的语句,如果都不符合执行default后面的语句
var score = arc4random_uniform(101) //小子,考了多少分啊
switch score{
case 0...59:
print("Fail")
case 60...79:
print("Lucky boy")
case 80...89:
print("Not bad")
case 90...99:
print("Good boy")
case 100:
print("Are you kidding me")
default:
print("error")
3.循环
1.for循环
格式:for 变量名 in (区间){语句} 功能:每次循环都依次在区间中取一个数(从小取到大),将取出来的数保存到变量中,然后执行大括号中的语句
来个1到100求和
var sum = 0
for var i in(1...100){
sum += i
}
print(sum)
双层循环 外层for循环负责层数,里层for循环负责每一层的个数
for var i in 1...5{
for var j in i...5{
print("*",terminator:"") //terminater:""不换行标志
}
print("") //换行
}
上面的代码的输出结果是:
***
**
***
**
2.while循环
格式:while(条件语句){循环体}
规律:每次判断条件语句是否为true,如果true就执行循环体里面的内容,否则就结束循环,执行循环后面的代码
我们用while循环来求1到100中的偶数 的和
var x = 0
var sum = 0
while(x<=100){
sum += x
x += 2
}
print(sum)
3.repeat-while
格式:repeat{循环体}while(条件语句) 规律:先执行循环体,然后再判断条件语句结果是否为true,再继续执行循环,否则结束(特点:至少循环一次) 我们用repeat-while循环来求1到100当中能被5整除的数的和
var x = 0
var sum = 0
repeat{
sum += x
print(x) //我们来看看找出的数是不是能被5整除
x += 5
}while(x<=100)
print("the fucking sum is \(sum)")
4.continue(循环控制)
我们用continue控制循环的方法来求1到100的奇数和
var x = 0
var sum = 0
for x in 0...100{
if x % 2 == 0{
continue //这时求到的是偶数,所以continue下一个循环是奇数
}
sum += x
}
print(sum)
5.break
作用:直接结束当前的这个while或者for循环,结束整个循环 与continue的区别:continue结束本次循环,不执行continue后面的语句;break是一旦条件发生,结束那个循环体
我们来求1000~10000中第一个被77整除的数
for x in 1000...10000{
if x % 77 == 0{
print(x)
break //找到第一个之后无需再找
}
}
4.数组
1.认识数组
1.Swift中提供三种集合类型:数组、集合、字典
2.数组是有序集合,集合是无序集合,字典是通过键值对的形式存储数据的无序集合
3.Swift中的数组和C语言的数组一样,只能用来存储相同类型的数据
我们先来学习一下怎么创建空数组
var array = [Double]()
var array1:[Int] = []
var array2:[String] = [String]()
var array3 = Array<Int>()
var array4:Array<String> = []
- 创建一个有默认值的数组,下面代码表示3重复次数10
let array = [Int](repeatElement(3,10))
- 创建一个有序范围数组(…)表示
let array2 = array(1...10)
- 数组计数:count,空否:isEmpty
array.count
array.isEmpty
- 添加同类型数组
array.append(2)
array += array2
- 获取元素
array[1];//第二个元素
-
插入insert
array.insert(9,at:2)
- 移除remove
array.remove(at:1)
5.set集合
无序不重复,适合存储具有唯一性的数据,userId。
var numbers : Set = [1,2,3,1,4] //这次打印出来是2,3,1,4(不一定,肯1肯定出现一次)
插入,移除不需要加位置
numbers.insert(5)
numbers.remove(1)
是否包含contains
numbers.contains(1) //true
转换为数组 sorted
let array = numbers.sorted()
另外集合还有交集intersects,并集uinion,差集subtract,补集exclusiveor概念
6.字典Dictionary
-
定义dictionary<键类型,值类型>,或[键类型,值类型]
var a : Dictionary<String,String> var b : [String,String]
- 字面量创建
var responseObject = ["message":"succeed","code":"520","userID":"skyFucker",];
- 添加或更新
responseObject["addTime"] = "2015-03-26 19:52:11"
responseObject["message"] = "fail"
- 移除,把值设为nil
responseObject["userID"] = nil
- 循环一个字典,键值对有两个,用元组变量
for (key,value) in responseObject{
print(key,value)
}
- 1.单独使用其中键或值,使用keys或values
for key in responseObject{
print(key)
}
- 2.把键值对分离成数组,用【数组类型](字典变量.keys)
let keys = [String](responseObject.keys)
let values = [String](values)
7.函数
- func函数名(参数1:类型,参数2:类型…) -> 返回结果的类型{执行语句}
- 调用:var 变量名称 = 函数名(参数1,参数2…)
- func 函数名(){} //不带参数类型的函数
- 调用 函数名()
func add(x: Int,y: Int) -> Int{
return x + y
}
var a = add{x: 3, y: 4} //输出结果为7
- 函数变形,在参数里面内嵌另一个函数
func calculate(x: Int,y: Int method: (Int,Int)->Int) -> Int{
return method(x,y)
}
func multiply(x: Int,y: Int) -> Int{
return x * y
}
calculate(x: 3,y: 4,method: multiply) //30
8.闭包
闭包是一种函数的简写形式,省去函数名,把参数和返回值放入花括号里。
- sorted函数用于对数组排序,只接受一个函数型参数,描述排序逻辑
var city = ["New York","Paris","London","Tokyo"];
var cityOrder = city.sorted() //["L","N","P","T"];
fun invertedOrder(a: String,b: String) -> Bool{
return a > b
}
var cityInvertedOrder = city.sorted(by:invertedOrder) //倒序["T","P","N","L"]
以上是普通写法,下面用闭包来改写:
var cityOrderClosure = city.sorted{(a,b) -> Bool in
return a > b //省略了函数名,参数类型
}
var cityOrderClosure = city.sorted{(a,b) in
a > b //还可以省略了返回类型,return关键字
}
var cityOrderClosure = city.sorted{ $0 > $1}//用$0代表第一个参数
二、面向对象
- 属性是一个类/结构体/枚举关联的变量
- 实例属性:实例化才能使用
- 存储属性:保存单个类型的变量
1.实例属性
class user{
let id = ""
var money = 0
}
let wellyoung = user()
wellyoung.id = 666
wellyoung.money = 888
1.计算属性:由其他属性计算得出,由getter和setter组成
2.getter获取器(必须):描述属性如何计算及返回语句,形式:get{语句和返回}
3.setter设置其(可选):有新值(newValue)后如何影响其他属性。形式set{语句}
struct coordinate{
var x = 0,y = 0
}
enum moveWay{
case walk
case run
case ride
case transfer //传送
}
case ADC : character{
var userCoordinate = coordinate()
var userMoveWay = moveWay.walk
var currentCoordinate:coordinate{
get{
switch userMoveWay{
case .walk:
userCoordinate.x += 1
userCoordinate.y += 1
case .run:
userCoordinate.x += 3
userCoordinate.y += 3
case .ride:
userCoordinate.x += 10
userCoordinate.y += 10
case .transfer:
userCoordinate.x += 100
userCoordinate.y += 100
}
return userCoordinate
}
set {
userCoordinate = newValue
}
}
}
var EZ = ADC()
EZ.currentCoordinate //x1 y1 走了一步所以坐标为(1,1)
EZ.userMoveWay = .run
EZ.currentCoordinate // x4 y4
EZ.userMoveWay = .transfer
EZ.currentCoordinate // x104 y 104
//计算属性的setter方法,影响其他属性
EZ.currentCoordinate = coordinate(x:2000,y:90)
EZ.currentCoordinate //x2000 y90
4.属性监视器:对属性值得变化进行响应
- willSet:事前响应,新值newValue
- didSet:事后响应,旧值oldValue
class XP{// XP 是experience 游戏术语经验值
var totalXP = 0{
willSet{
print("currentTotalXPIs:\(newValue)!")
}
didSet{
print("add\(totalXP - oldValue)XP!")
}
}
}
var xp1 = XP()
xp1.totalXP = 1000 //查看控制台 并尝试修改经验值观察变化
2.类型属性
类型属性:属于类型固有的,实例不能调用
对于类,计算型的类型属性,前面加关键字class可被子类重写 override
class livingBeings{
class var inheritance : String{ //前面必须加class或者static静态 才能调用 inheritance遗传方式
return "RNA"
}
}
livingBeings.inheritance //RNA
class humanBeings:livingBeings{
override class var inheritance : String{ //前面必须加override才能重写不然还是调用父类的属性打印 RNA
return "DNA"
}
}
humanBeings. inheritance //DNA
再来看看结构体
struct shoppingOnline{
static let url = "http://www.taobao.com?cate="
var category = ""
var shareUrl: String{
return shoppingOnline + category
}
}
let seafood = shoppingOnline(category:"seafood")
seafood.shareUrl //http://www.taobao.com?cate=seafood
3.实例方法
- 方法是一个类/结构体/枚举关联的函数,分为实例方法和类方法
- 实例方法:定义和使用与前面讲的函数相似
- 引用实例自身 self.表示,在swift中可以省略self
enum Monster: Int{
case sheep = 10,
snake = 100,
dragon = 1000
}
struct EXPTimes{
var open = false //是否开启多倍经验
var times = 1
}
class RMBPlayer{
var exp = 0
var EXPTimes = EXPTime()
func hang(){
exp += 50
print("Total EXP is\(exp)"
}
func shot(monster:Monster,EXPTimes:Int){
exp += (monster.rowValue * EXPTimes)
print("EXP \(exp)")
}
}
var player1 = RMBPlayer()
player1.hang()
player1.shot(monster:Monster.snake,EXPTimes:2)
var player2 = RMBPlayer()
player2.hang
4.类型方法
类型方法属于类型本身,无需实例化就可以使用,方法前加关键字 static
class player {
static var nickname = "wellyoung"
class func server(){
print("\(nickname),you are in district 13 ")
}
}
player.server
class OsakaPlayer : Player{
override static func server(){
print(nickname,"you are in 大阪府")
}
}
OsakaPlayer.server()
5.继承
继承:class之间的父子关系的提现 ,struct结构体和枚举没有继承
- 子类可以继承父类的属性和方法
class Vehicle{
var speed = 0
var desc: String{
return "speed per hour \(speed)km/h"
}
func makeNoise(){
}
}
class Bicycle:Vehicle{
var hasEngine = false
}
let bicycle = Bicycle()
bicycle.speed = 30
bicycle.desc
bicycle.hasEngine
- 子类可以根据需要,修改继承来的属性和方法 (多态)
class HSR :Vihicle{//高铁
override func makeNoise{
print ("dududu")
}
}
let hsr = HSR()
hsr.makeNoisy()
6.初始化
描述类/结构体/枚举实例化时,属性如何给初始值的方法。形式init(){}.此方法称为构造器
- 类的定义没有给属性默认的值,在init在指定
class RoomTemperature{
var season:String
var temp: Int
init(season:String,temp:Int){
self.season = season
self.temp = temp
}
}
let temp1 = RoomTemperature(season:"Spring",temp:20)
temp1.season
- 结构体定义不需要指定默认的值,因为默认提供一个包含所有属性初始化的构造器
struct RoomTemp{
var season:String
var temp:Int
}
let temp2 = RoomTemp(season:"summer",temp:24)
- 便利构造器:可以通过对主构造器的包装,实现便利的初始化
class Food{
var name:String
var temp: Int
init(name:String){
self.name = name
}
convenience init(){
self.init(name:"rice")
}
}
let food = Food() //rice
- 可失败构造器:针对可能失败的初始化,如图片名不存在的时候
struct Animal{
let name:String
init?(name:String) {
if name.isEmpty{
print("name is empty!")
return nil
}
self.name = name
}
}
let cat = Animal(name:"") //nil
7.错误处理
- 可选类型仅处理值确实,错误处理可以针对不同的出错原因对不同的应付
- 一个函数可以加上throw关键字,表示可以处理错误,这个函数的调用者可以捕获这个错误并进行应对
func Foo() throws{
print("hello Wellyoung")
}
- 当你调用可以抛出错误的函数,须在前面加try关键字
try Foo
- 处理更细节的错误情况 错误类型须遵从 ErrorType协议
enum LearningSwift:Error{
case noMethod,noReading,noProgramming,noTool(tool:String){
}
}
func appleDeveloper(method:Bool,style:Bool,hasTool:Bool) throw{
guard method else{
throw LearningSwift.noMethod
}
guard style else{
throw LearningSwift.noReading
}
guard hasTool else{
throw LearningSwift.onTool(tool:" no MacPro")
}
}
var money = 7000
func buy(tool:String){
if money >= 6000{
money -= 6000
print("you have bought",tool,"cost 6000$ balance:",money)
}else{
print("funf shortage")
}
}
do{
try appleDeveloper(method:true,stle:true,hasTool:false)
} catch LearningSwift.noMethod{
} catch LearningSwift.noReading{
} catch LearningSwift.noTool(let tool){
buy(tool:tool)
}
- 有时候仅关心结果有无,可使用 try ? try!来忽略错误细节
if let result = try! appleDeveloper(method:true,style:true,hasTool:false){ print("succed") }else{ print("fail") } try! appleDeveloper(method:true,style:true,hasTool:false) //强行报错
二、面向协议编程
协议:方法、属性或一段功能
- 协议可被类、结构体和枚举领养从而长大成人
- 任何满足协议的需求的类型,被称为遵从该协议
protocol AProtocol{
}
protocol BProtocol{
}
- 领养 若干个协议,用逗号分隔,结构体没有继承但能遵从协议,广义的讲结构体通过遵从协议从而实现了继承的功能
struct AStruct: AProtocol, BProtocol{
}
- 超类(父类)在协议之前
class Name{
}
class GivenName:Name, AProtocol, BProtocol{
}
1.属性协议
要求遵从者实现以指定的名称属性,但具体实现是实例属性或类型属性并不关心
- 可以指定要求实现getter或getter + setter,属性定义为变量var
protocol FileAccessPrivilege{// 文件读写权限
var readOnly:Bool {get}
var readWrite:Bool{get set}
}
protocol AccessUrl{
static var link:String{ get }
}
- 遵从实例属性协议1
protocol FullName{
var fName:String{get}
var gName:String{get}
}
struct Student:FullName{
var gName:String
var fName:String
}
struct Teacher: FullName{
var gName:String
var fName:String
}
var student = Student(gName:"Tom",fName:"Hardy")
student.fName
student.gName
- 遵从实例属性协议2
class SomeBoby:FullName{
var title:String?
var name:String
init(title:String,name:String){
self.title = title
self.name = name
}
var gName:String{
return name
}
var fName:String{
return title ?? "no name"
}
var desc:String{
return self.fName + self.gName
}
}
var someone = SomeBody(title:"Royol",name:"Alex")
someone.gName
someone.fName
var nobody = SomeBody(title:nil,name:"Tom")
nobody.gName //Tom
nobody.fName //no name
nobody.desc // no name Tom
2.方法协议
定义时没有花括号执行体,实现仅要求名称相同
- 作用:可以让一个类/结构体/枚举的方法 分解为更小的组合,从而更灵活
protocol AMethod{
static func foo()
}
class A : AMethod{
class func foo(){
print("holy shit")
}
}
- 实例方法协议
protocol RandomGenerator{ //随机数发生器
func randomInt() -> Int
}
struct RandomNumber: RandomGenerator{
func randomNumber() -> Int{
return Int(arc4random())
}
}
let number = RandomNumber()
number.randomNumber() //范围很大
struct RandomNumberInTen: RandomGenerator{
func randomNumber() -> Int{
return Int(arc4random()) % 10 //对10 求余 范围就是0——10
}
}
let smallNumber = RandomNumberInTen()
smallNumber. randomNumber //0~10