基本數據類型
-
常見的數據類型:
- 值類型(value type)
- 枚舉
enum / Optional
- 結構體
Bool/Int/Float/Double/Character/String/Array/Dictionary/Set
- 引用類型(reference type):
類(class) - 整數類型
在32位的平臺中Int等價於Int32、64位平臺Int等價於Int64
Int8/Int16/Int32/Int64/UInt8/UInt16/UInt32/UInt64
- 浮點類型:
Float
(32位,精度只有6位)
Double
(64位,精度至少15位)
func valueFunc() {
var floatDemo: Float? = 10
var doubleDemo: Double? = 29
enum TestEnum{
case one,two,three
}
struct SomeStruct{
var age = 10
var height = 167
}
}
- 字面量,
直接賦值
,編譯器可以推斷其類型的內容
let bool = true
let intDecimal = 17 //十進制
let intBinary = 0b1001010 //二進制
let intHexdecimal = 0x12 //十六進制
let intOctal = 0o21 //八進制
let doubleDecimal = 125.0 //十進制 等價於1.25e2
- 類型轉換
func typeToChange() {
//整數轉換
let int1: UInt16 = 2_000
let int2: UInt8 = 1
let int3 = int1 + UInt16(int2)
//字面量可以直接相加,字面量本身沒有明確的類型
let int4 = 123 + 12.344
}
- 元組
func tupleDemo() {
//如何創建一個404錯誤的元組?如何取值?
let http404Error = (404,"404 error, not found")
print("The status is \(http404Error.0)")
//如何對元組取值
var firstValue = http404Error.0
var secondValue = http404Error.1
//取到元組內容
let (status, message) = http404Error
print("status code is \(status), message:\(message)")
//忽略某個元組參數
let (careStatus, _) = http404Error
print("i only care status:\(careStatus)")
}
- 條件判定(if 後面只能是Bool類型,可以省略小括號,大括號不能省略)
func loginJudge() {
let age = 5
if age >= 22 {
print("ready to marry")
}else if age > 18{
print("just in adult")
}else{
print("just a child")
}
-
while
的使用
/*
循環
while使用
repeat...while 相當於OC中的do...while循環
*/
func whileUse() {
var num = 5
while num > 0 {
print("循環我...")
num -= 1
}
var repeatTimes = 5
repeat{
print("look here ...")
repeatTimes -= 1
}while repeatTimes > 0
}
-
for
循環使用
func forLoopUse() {
let names = ["Zhang", "Lee", "Chen", "Gong"]
//...是閉區間方法,返回閉區間
for i in 0...3 {
print(names[i])
}
//使用range遍歷
let range = 1...3
for j in range {
print(names[j])
}
var a = 1
let b = 3
for j in a...b {
print(names[j])
}
for _ in 0 ..< names.count {
print("for item")
}
}
- 區間運算符
/*
區間運算符
通過創建區間運算符判定指定數的範圍類型
*/
func rangeCreatAndUse() {
let range = ...10
print(range.contains(20))
print(range.contains(11))
}
/*
使用區間運算符遍歷數組,區間運算符:[1...b]/[1...]/[...1]/[..<2]
*/
func rangUseInArray() {
let names = ["Zhang", "Lee", "Chen", "Gong"]
for name in names[0...3] {
print(name)
}
for name in names[...3] {
print(name)
}
for name in names[..<4] {
print(name)
}
}
- 區間類型
- ClosedRange<T> 閉區間
- Range<T> 半開區間(前閉後開)
- PartialRangeThrough<T> 部分區間
//練習:使用區間判斷字符是否在字母範圍,請利用區間特性
func rangeType() {
let _: ClosedRange<Int> = 1...3 //閉區間
let _: Range<Int> = 1..<3 //半開區間(前閉後開)
let _: PartialRangeThrough<Int> = ...5 //部分區間
let character: ClosedRange<Character> = "a"..."z"
print(character.contains("B"))
let charRang: ClosedRange<Character> = "\0"..."~"
print(charRang.contains("B"))
}
//從4開始累加2,不超過11,篩選出對應的數據值,可以使用stride方法來進行跳躍
func rangeContainThrough() {
let allRang:ClosedRange<Int> = 1...100
// var indexValue = 0
// switch allRang.startIndex {
// case .inRange(let preIndex):
// indexValue = preIndex
// default:break
// }
//
// print("position [0] = \(indexValue)")
for targetValue in stride(from: 4, through: 100, by: 2) {
print(targetValue)
}
}
-
Switch
語句- case/default後面不能夠添加大括號
- Swift中的case不用添加break,默認會執行到下一個case到來
注意點:
1. case、default 後面至少需要跟一條語句
2. 如果不想做任何事,可以在最後添加break語句結束
func switchUse() {
let num = 1
switch num {
case 1:
print(num)
case 2:
print(num)
default:
print(num)
}
}
/*
連續執行多行case,如何操作?
可以使用fallthrough操作
*/
func mutiCaseExec() {
let num = 1
switch num {
case 1:print(num); fallthrough
case 2:print(num); fallthrough
case 3:print(num); fallthrough
case 4:print(num)
case 5:print(num)
default:break
}
}
/*
switch 自定義枚舉的時候,如果保證所有的枚舉都列舉完成,
那麼可以不必使用default來處理默認情況
*/
func associateEnumValue() {
enum Answer{case right, wrong}
let finishAnswer = Answer.right
switch finishAnswer {
case .right:print("answer result is \(finishAnswer)")
case .wrong:print("answer result is \(finishAnswer)")
}
}
/*
switch case如何使用複合類型來判定
*/
func moreTypeCase() {
let string = "Jack"
switch string {
case "hello", "Lee", "Wang": print("rich man~")
case "Jack": print("poor man~~")
default: print("Not Found")
}
}
/*
Switch
1. 使用區間Range進行值匹配
2. 使用元組進行case匹配
*/
func switchRangeCase() {
let score = 45
switch score {
case 0..<60: print("Not Ok")
case 60..<80: print("Just So So")
case 80..<90: print("Good")
case 90..<100: print("Woundful")
default:print("So bad")
}
let infoMan = (84, "Good")
switch infoMan {
case let (cScore, cLevel): print("score\(cScore), level:\(cLevel)")
case let (_, cLevel): print("level:\(cLevel)")
default:break
}
}
- 值綁定
使用let = option case 進行值綁定
/*
值綁定
使用let = option case 進行值綁定
*/
func valueBind() {
let point = (2, 0)
switch point {
case (let x, var y): print("x: \(x), y:\(y)")
case (_, var y): print("x: -, y:\(y)")
case (let x, _): print("x: \(x)")
default:break
}
}
- 條件過濾
where
/*
where 條件過濾
*/
func whereFiliterUse() {
var point = (1, 2)
switch point {
case (let x, let y) where x == y: print("y=x line in dicarl line")
case (_, let y) where y==0: print("y line in dicarl line")
case (let x, let y) where (x>0 && y>0): print("location is in first part view")
default:break
}
}
- 標籤語句
outer
/*
標籤語句(通過outer標籤語句能夠簡化跳轉邏輯)
outer:
*/
func outerUse() {
outer: for k in 1...4 {
for j in 8...16 {
if j == 10 {
continue outer
}
if k == 3 {
break outer
}
print("k == \(k), j=\(j)")
}
}
}
函數的定義
- 函數的隱式返回
對於只有一行的語句,可以省略返回return關鍵字,這種省去返回return關鍵字的操作叫做隱式返回.
class FuncUse {
//帶返回值
static func pi() -> Double {
return 3.14;
}
//加法
static func sum(v1: Int, v2: Int) -> Int {
return v1 + v2
}
//加法簡化
static func sumSlim(v1: Int, v2: Int) -> Int {v1+v2}
}
/*
返回元組,實現多值返回
*/
func tupleReturnUseTypeAlias() -> (userName: String, age: String, className: String) {
(userName: "String", age: "String", className: "String")
}
- 函數默認參數值
這裏的方法參數設置與C++有點區別,
C++中參數值有限制,必須從右向左設置
對於沒有設置默認值的方法參數是不能夠省略的
而Swift中由於存在參數標籤,所以不用按順序進行設置
例如下面的方法調用:
Swift:self.funcDefaultParamter(age: 28)
c++: self.funcDefaultParamter("lcc",28,"workMan")
func funcDefaultParamter(name: String = "lcc", age: Int, job: String = "none") {
print("name:\(name), age:\(age), job:\(job)")
}
- 可變參數(...)
- 可變參數在取值的時候使用遍歷取值
- 一個方法最多隻有一個可變參數
- 緊跟可變參數後面的參數不能夠省略標籤
func moreParameterIngoreTag(_ numbers: Int..., eachItem: (Int)->()) -> Int {
var sum = 0
for item in numbers {
eachItem(item)
sum += item
}
return sum
}
func moreParamterUse(_ numbers: Int...) -> Int {
var sum = 0
for number in numbers {
sum += number
}
return sum
}
- 函數重載
- 返回值類型與函數重載沒有關係
- 默認參數值與函數重載一起使用的時候如果產生歧義,編譯器不會報錯,優先調用匹配完全一致的方法
func someFunc() {
print("source func")
}
func someFunc(v1: Int, v2: Int) {
print("change func use to sum: \(v1 + v2)")
}
func someFunc(v1: Int, v2: Int, v3 :Int = 20) {
print("more parameter count: \(v1 + v2 + v3)")
}
- 輸入輸出參數
inout
可以在函數內部調用外界的方法,比較典型的範例就是通過元組實現兩個數字的交換
//傻子方法
func swapNum(numberOne: inout Int, numberTwo: inout Int) {
let sourceTuple = (numberOne, numberTwo)
let result = (sourceTuple.1, sourceTuple.0)
numberOne = sourceTuple.1
numberTwo = sourceTuple.0
print("交換之前:\(sourceTuple), 交換之後\(result),numberOne:\(numberOne),numberTwo:\(numberTwo)")
}
//優雅方法,使用元組直接能夠交互
func swapNum(numberOne: inout Int, numberTwo: inout Int, des: String = "") {
(numberOne, numberTwo) = (numberTwo, numberOne)
}
- 內聯函數
@inline
在Swift編譯器
中默認是開啓自動轉換內聯函數的功能的實質:將函數調用展開成函數體。
注意:
1. 函數體比較長的不會被轉換成函數體
2. 遞歸調用不會轉換成函數體
3. 包含動態派發不能夠轉換成函數體
func buildToChange() {
print("transform to me")
}
//關閉內聯
@inline(never) func inlineUse() {
print("即使開啓編譯器優化,也不會被內聯")
}
//強制內聯
@inline(__always) func inlineOnAlways() {
print("即使代碼段很長,也會被內聯,除了動態派發的函數以及遞歸調用的函數外")
}
- 函數類型
函數類型包含以下兩個重要組成:
- 形式參數類型
- 返回值類型
func funcTest(parameter: String...) -> (String) {
var strUnition = ""
for str in parameter {
strUnition.append(str)
}
return strUnition
}
print(self.funcTest(parameter: "leo ", " is"," the", " best", " programmer"))
- 使用函數類型作爲函數的參數進行傳遞
-
@autoclosure
的使用,對於沒有參數的函數作爲參數的話可以添加@autocclosure
關鍵字讓函數的調用更加簡潔高效 - 正常函數調用,如果將函數作爲參數進行傳遞的話,可以考慮使用
$
符獲取參數內容
func printSumResult(n1: Int, n2: Int, sumAdd: @autoclosure()->(Int)) {
print(sumAdd())
}
func printSumResult(n1: Int, n2: Int, sumAdd: (Int, Int)->Int) {
print(sumAdd(n1, n2))
}
self.printSumResult(n1: 1, n2: 2, sumAdd: 3)
self.printSumResult(n1: 32, n2: 29) {$0+$1}
self.printSumResult(n1: 32, n2: 11) { (num1, num2) -> Int in num1 + num2}
- 使用函數作爲返回值進行傳遞操作
返回值是函數類型的函數,也叫做高階函數
func returnFunUse() -> (Int, Int) -> Int {
return {$0+$1}
}
- 類型別名
typealias
typealias LCInt = Int
typealias LCFloat = Float
func typealiasUse(age: LCInt, score: LCFloat) {
print("age:\(age), score:\(score)")
}
- 嵌套函數
在函數中嵌套一個函數。
func funcInFunc() -> ((String, Int) -> () , (Int, Int) -> (Int)) {
func result(usrName: String, age: Int){
print("I get your name:\(usrName), and your age:\(age)")
}
func countTwoSum(num1: Int, num2: Int) -> Int{num1 + num2}
return (result, countTwoSum)
}
var (funcOne, funcTwo) = self.funcInFunc()
funcOne("lcc", 25)
print("count result:\(funcTwo(24, 64))")
self.funcInFuncSignal()(1,3)
-
枚舉的基本用法
- 值類型枚舉
- 關聯值類型
將值類型成員與其他類型的值關聯在一起,可以起到關聯變量值存儲的作用,在使用的枚舉,抽象表達某些功能的時候會變得異常方便
注意:值類型與關聯值類型的空間存儲區別
1. 如果枚舉是基本的值類型,那麼枚舉在內存空間的容量是固定的,因爲本質存儲的是原始值,默認分配1個字節的空間內容來進行存儲
2. 如果枚舉是關聯類型的存儲,那麼要根據枚舉的類型來確定其內存空間的佔用大小,通常選擇枚舉關聯值最大的爲存儲空間,還要加上原始值的存儲(1個字節),最終算出來的是其真實佔用的空間大小
佔用空間大小與實際內存分配的大小區別
佔用空間大小是通過當前數據類型佔用的空間大小累加的總和,而在實際分配過程中由於iOS系統通常會採用內存對齊的方式去分配真實的空間,通常是8個字節的整數倍。所以由於內存對齊的原因,在實際分配內存上,可能分配的空間大於實際所佔用的內存空間
//以下實際佔用了 32+1 = 33 個字節的空間大小,實際分配了40個字節的空間大小
enum Password {
case number(Int, Int, Int, Int)
case other
}
//值類型,僅分配1個字節存儲原始值內容
enum Direction {
case top, left, bottom, right
}
//關聯值類型
enum LoadServerMethod {
case LoadFirst(url: String)
case LoadSecond(url: String)
case LoadFinish(finish: (Any)->())
}
func testEnum() {
let gogoUp = Direction.top
// let requestServer = LoadServerMethod.LoadFirst(url: "http://www.baidu.com")
let finishClosure = LoadServerMethod.LoadFinish { (data) in
print("server data:\(data)")
}
switch gogoUp {
case .top: print("top")
case .left: print("left")
case .bottom: print("bottom")
case .right: print("right")
}
switch finishClosure{
case .LoadFirst(let url): print("請求的地址:\(url)")
case .LoadSecond(let url): print("請求的地址:\(url)")
case .LoadFinish(let finish): finish(["data":"nil"]);
}
}
- 枚舉的用法
枚舉成員可以使用相同的類型的默認值進行預先關聯,默認設置的值叫做原始值,枚舉原始值類型如果是Int、String,Swift
會默認分配其原始值
func enmuSourceValue() {
enum DefaultIntEnum: String{
case top, left, bottom, right
}
enum TypeSource: Int{
case age = 18
case birth = 19701010
case idCard = 00000000000
}
//打印出原始值
print(DefaultIntEnum.top.rawValue)
print(DefaultIntEnum.top)
}
- 枚舉遞歸
- 遞歸枚舉類似於函數的遞歸,是枚舉內容本身調用枚舉本身
- 遞歸枚舉可以用來按層級存儲關聯數值,在使用的時候結合業務
- 一般使用遞歸函數配合來進行switch..case的判定
func indirectEnum() {
enum AirthExpr {
case number(Int)
indirect case sum(AirthExpr, AirthExpr)
indirect case difference(AirthExpr, AirthExpr)
}
func traverseEnum(airthNum: AirthExpr) -> Int {
switch airthNum {
case .number(let num): return num
case let .sum(airthExpOne, airthExpTwo): return traverseEnum(airthNum: airthExpOne) + traverseEnum(airthNum: airthExpTwo)
case let .difference(airthExpOne, airthExpTwo): return traverseEnum(airthNum: airthExpOne) - traverseEnum(airthNum: airthExpTwo)
}
}
let five = AirthExpr.number(5)
let four = AirthExpr.number(4)
let sumAdd = AirthExpr.sum(five, four)
let diffEnum = AirthExpr.difference(five, four)
print("add result :\(traverseEnum(airthNum: sumAdd))")
print("different result :\(traverseEnum(airthNum: diffEnum))")
}
- 可選類型
聲明某個變量爲可選,直接在變量的類型後面添加?即可
對於可選類型的變量或者常量,有兩種方式可以拿到其原始值:- 強制解包
- 可選鏈操作
可選可以理解爲一層包裝盒子,盒子裏裝的是真實數據
- 如果爲nil,那麼它是一個空盒子
- 如果非nil,那麼盒子裝的就是被包裝的數據
!是強制解包的標識符,如果對nil的可選類型進行強制解包,將會產生運行時錯誤(Fatal error:...)
注意:
數組返回的數值不是可選類型的數值,因爲當數組越界的時候就已經發生崩潰,並不能拿到帶有歧義的數值(nil或者有數值),而字典獲取的數值爲可選數值
func unwrappTypeUse() {
var age: Int?
//直接相加由於age是可選類型所以會報錯
// age+=10
//通過!來進行強制解包
print(age!+=10)
}
- 解包之可選綁定
- 如果包含內容就自動解包,把可選內部包裝的值賦值給一個臨時變量 var 或者常量 let,並返回 true, 否則返回false
- 如果存在多個值,可選綁定可以通過逗號分開,注意不能使用&&分割
func unwrappingBindUse() {
let num: Int? = 10
let addTo: Int? = nil
if let tmpNum = num,
let _ = addTo{
print("含有內容:\(tmpNum)")
}
}
-
while
使用可選綁定
/*
while中使用可選綁定
遍歷數組,將遇到的整數都加起來,如果遇到複數或者非數字,停止遍歷
*/
func bindLetWhileLoop() {
let strs = ["10", "20", "abc", "-20", "30"]
var index = 0
var sum = 0
while let num = Int(strs[index]), num > 0 {
sum += num
index += 1
}
print("運算結果:\(sum)")
}
- 合併空運算符
??
- 被修飾的是可選類型
- 合併的備選常量或者變量與被修飾的類型要保持一致
- 如果備選不是可選類型,返回的時候會自動進行解包操作
注意:
空合併運算符(??)是如何實現的?爲什麼在返回默認值的時候要使用閉包來實現,直接返回默認內容不可以嗎?
1. 包裝了一個函數裏面實現的public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T
2. 內部實現使用了switch判定類似於以下的操作,使用運算符重載操作
運算符重載??實現可能如下:
func ??<T>(optional: T?, defaultValue: @autoclosure () throws -> T) rethrows -> T{
switch optional {
case .some(let optional): return optional
case .none: return try!defaultValue()
}
}
- 多個空合併運算符
??
一起使用
/*
多個 ?? 一起使用
*/
func mutiDefaultValueUse() {
let a: Int? = 1
let b: Int? = 2
let c = a ?? b ?? 3 //c是Int,1
let d: Int? = nil
let e: Int? = 2
let f = d ?? e ?? 3 //f是Int, 2
}
-
??
與if let
配合使用
/*
?? 與 if let 配合使用
等同於 if a! = nil || n != nil
*/
func defaultWithChooseBind() {
let a: Int? = nil
let b: Int? = 2
if let c = a ?? b {
print("result--->\(c)")
}
}
-
guard
語句
- 當
guard
語句條件爲false
時,會執行大括號裏面的內容,否則正常執行 -
guard
時候提前過濾不滿足當前方法或者函數執行的條件 - 當使用
guard
語句進行可選綁定的時候,綁定的常量let
、變量var
也會在外層作用域使用
func guardUseStatement(age: Int, level: Int) {
guard age > 18, level > 50 else {
print("未成年人禁止瀏覽")
return
}
print("一起看動畫片啊~")
}
- 隱式解包
- 某些情況下,有些可選類型變量一開始設定就直接有值
- 在確定可選類型內容一直有值的情況下,可以通過在變量後面添加!的方法去除類型檢查
- 去除類型檢查之後,每次獲取的可選類型變量將會隱式進行解包取出其中包含的數值
func unwrappingValueUse() {
var num: Int! = 10
var choose: Int? = 20
print("隱式解包\(num)")
print("強制解包\(choose!)")
}
- 字符串查值
func strDesprint() {
let age: Int? = 10
print("age:\(age ?? 0)") //這樣打出來的內容是可選類型
print("ageDes:\(String(describing: age))")
}
- 多重可選項
多重可選項可以理解爲多重可選的包裝,在取值的時候需要格外注意,要分層取值。
func moreUnwrappingValue() {
let num: Int? = 10
let userone: Int?? = 20 //被包裝了兩次,解包的時候需要解包兩次纔行
let userTwo: Int??? = 30 //道理同上
let numValue = num!
let userOneValue = userone!!
let userTwoValue = userTwo!!!
print("當前內容:\(numValue), \(userOneValue), \(userTwoValue)")
}