Swift学习笔记

Swift

Posted by wellyoung on June 23, 2016

Swift学习笔记

Markdown语法

一、基础语法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