SwiftiOS开发iOS Developer

Swift快速上手笔记

2017-06-26  本文已影响67人  AlienJunX

可选项

Optional可以让我们摆脱很多不必要的判断和取值,声明变量在类型后面加上?的语法

class Toy {
    let name: String
    init(name: String) {
        self.name = name
    }
}

class Pet {
    var toy: Toy?
}

class Child {
    var pet: Pet?
}

if let toyName = xiaoming.pet?.toy?.name {
    // 通过多级守护安全取到值
}

还有很多高级用法,后面慢慢研究。

if let & guard let

用于守护操作

// MARK: - if let / gucard let 用法
func ifletDemo() {
    let i:Int? = 10
    
    if let a = i {
        // 此处a 解包了i,如果a解包是nil则不成立
        print(a)
    } else {
        print("i is nil")
    }
    
    // 此处使用guard 减少逻辑分支层级,a在后续使用已经被解包
    guard let a = i else {
        print("i is nil")
        return
    }
    
    print(a)

}

switch

swift 的switch比OC要灵活很多,支持多种数据类型,Int、String、浮点,结构体, 并且支持使用元组值绑定,结构体值绑定。

let n = 10

switch n {
case 1:
    print("\(n)")
case 10:
    print("\(n)")
default:
    print("default")
}


// 多种类型, 字符串、Bool、结构体、浮点
var str = "my"
switch str {
case "my":
    print("case my")
    fallthrough
case "d":
    print("1") //被输出
default:
    print("default")
}

// 运算区间
switch n {
case 0 ..< 5 :
    print("0~5")
case 5 ... 10 :
    print("5~10")
default:
    print("default")
}

// Value Binding  值绑定,适合和enum合用
let request = (6,"success")
switch request {
case (let errorCode, let state):
    print("\(state),\(errorCode)")
case (let errorCode, _):
    "error code is \(errorCode)"
}

// enum 结构值绑定
enum Result {
    case Success(json: String, isSuccess: Bool)
    case Fail(error: String)
}

let r = Result.Success(json: "{}", isSuccess: true)

switch r {
case Result.Success(let json, let isSuccess):
    print("\(json)")
default:
    print("default")
}

for

swift 3.0 已经去掉了 C 语言风格的for循环。

let array = [1, 12, 9, 4]

// 遍历数组
for i  in array {
    print(i)
}

// 条件区间
for i in 0...10 {
    print(i)
}

字符串

swift 中的字符串操作,如果遇到不方便操作的时候记得转为NSString

// 遍历字符串
for c in str.characters {
    print(c)
}

// 反序
for c in str.characters.reversed() {
    print(c)
}

// 转换成NSString
let ocStr = str as NSString

// 字符串长度
print(ocStr.length)
// 字节长度
print(str.lengthOfBytes(using: .utf8))

// 截取字符串
let substr = ocStr.substring(with: NSMakeRange(0, 5))
print(substr)

数组

// MARK: -遍历数组
func arrayDemo() {
    let myArray = [1, 2, 3]
    
    // 遍历
    
    // 元组1
    print("-----遍历数组1....")
    for e in myArray.enumerated() {
        print("\(e.offset), \(e.element)")
    }
    
    // 元组2
    print("-----遍历数组2....")
    for (of, el) in myArray.enumerated() {
        print("\(of),\(el)")
    }
    
    // 直接遍历
    print("-----遍历数组3....")
    for item in myArray {
        print(item)
    }

    
    // 反转数组
    print("-----反转数组....")
    for item in myArray.reversed() {
        print(item)
    }
    
    print("-----")
    for (of, el) in myArray.enumerated().reversed() {
        print("\(of),\(el)")
    }
}

// MARK: - 数组拼接
func arrayAppendDemo() {
    
    print("------数组拼接")
    var array = ["1", "test"]
    print(array)
    
    // 数组添加元素
    array.append("x")
    let array1 = ["a", "b", "c"]
    
    array += array1
    
    print(array)
    
    
    print("------")
    // 数组的拼接需要在同类型下进行
    var array2: [Any] = [2, "tt"] as [Any]
    let array3: [Any] = ["a", "b", "c"]
    array2 += array3
    
    print(array2)
}

字典

// 字典遍历
func demo() {

    // Swift3.1 必须要转为一个确定的类型 as [String:Any]
    let dic = ["name":"alienjunx", "age":20] as [String:Any]
    print(dic)

    // 直接遍历
    for (k,v) in dic {
        print("\(k),\(v)")
    }
    
    print("-----")
    for item in dic {
        print("\(item.key),\(item.value)")
    }
}

// 合并
func demo2() {
    print("-----合并")
    var dic1 = ["name":"alienjunx", "age":20] as [String:Any]
    print(dic1)
    
    let dic2 = ["height":90, "name":"老万"] as [String:Any]
    print(dic2)
    
    for (k,v) in dic2 {
        dic1[k] = dic2[k]
    }
    
    print(dic1)

}

// 删除
func removeDemo() {
    print("-----删除")
    var dic1 = ["name":"alienjunx", "age":20] as [String:Any]
    print(dic1)
    
    dic1.removeValue(forKey: "name")
    print(dic1)
}

函数

import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

// 函数返回一个String 类型
func myFunc() -> String {
    let i = "myFunc"
    return i
}

// 函数返回一个闭包
func loadMyName(name: String) -> ((String)->()) {
    print("\(name)")
    
    let result: ((String)->()) = {(rname: String)->() in
        
        print("\(rname),\(name)")
    }
    
    return result
}

loadMyName(name: "test")("my")

// 异步处理回调函数
// 参数的闭包需要进行声明 @escaping 逃逸闭包
func funcCallBack(completion: @escaping (_ json: String)->()) {
    DispatchQueue.global().async { 
        //// 耗时处理
        sleep(2)
        
        // 主线程回调
        DispatchQueue.main.async(execute: { 
            completion("ok")
        })
    }
}

funcCallBack { (resultStr) in
    print(resultStr)
}

闭包

与OC中的block一样,都是一段提前准备好的代码,通常用于参数传递进行处理回调结果

        // closure 是 '() -> ()' 一个闭包的类型
        // '=' 后面是实现这闭包  '闭包声明 in  实现'
        let closure: () -> () = {() -> () in
            print("closure")
        }
        
        /*
         1.如果闭包是无参数无返回,则实现时可以省略  in和前面的声明
         2.按照swift的类型推导,closure1的所属类型也可以不显示声明
         */
        let closure1 = {
            print("closure1")
        }
        
        
        // 调用闭包
        closure()

        // 有参数的闭包
        let closure2 = { (name: String) -> () in
            print(name)
        }
        
        closure2("alienjunx")
        
        
        //---------------------------
        // 函数中传递闭包作为回调
        closureFunc(callBack: { (name) -> () in
            print(name)
        })

        // 如果函数的最后一个参数是闭包,可以使用尾随闭包的方式简写
        closureFunc { (name) in
            print(name)
        }

        // callBack 是一个 (String) -> () 类型的闭包
        func closureFunc(callBack:(String) -> ()) {
            let myName = "testName"
            callBack(myName)
        }

??、?、!

let i:Int? = 10
// ?? 操作符,用于解包,如果Option中是nil,则返回 后面的值
let num = i ?? 0

问号?
-- 声明时添加?,告诉编译器这个是Optional的,如果声明时没有手动初始化,就自动初始化为nil
-- 在对变量值操作前添加?,判断如果变量时nil,则不响应后面的方法。
叹号!
-- 声明时添加!,告诉编译器这个是Optional的,并且之后对该变量操作的时候,都隐式的在操作前添加!
-- 在对变量操作前添加!,表示默认为非nil,直接解包进行处理

构造函数

构造函数在swift中都是以init命名

    override init() {
        name = ""
        
        // 会隐式调用super.init()
    }
    
    init(name: String) {
        self.name = name

        // 会隐式调用super.init()
    }
重写

只要父类提供了可重写的函数,那么在子类中可以重新实现此函数,在swift中
-- 子类先初始化后父类才初始化,这与oc完全是不一样的

class Person: NSObject {
    var name: String

    init(name: String) {
        self.name = name

        // 可不写super.init() 会隐式调用
    }
}

// 继承于Person
class Student: Person {
    var no: Int = 0

    // 重写父类构造函数
    override init(name: String) {
        super.init(name: name)
        self.no = 10
    }
}


let s = Student(name: "小明")
print("\(s.name) \(s.no)")

重载

函数名相同,参数类型和个数不同,重载不同的参数来满足不同的初始化操作,在OC中构造函数重载用的非常多。

class Person: NSObject {
    var name: String
    var title: String?

    // 构造方法1
    init(name: String) {
        self.name = name
    }
    
    // 构造方法2
    init(name: String, title: String?) {
        self.name = name
        self.title = title
    }
}
便捷构造函数

作为构造函数的一种补充方式。 本身不负责对象的创建和初始化工作,只是负责一些值的设置,并且可以通过条件判断,进行是否需要初始化,防止不必要的内存开销,只要不满足条件可以直接返回nil。
-- 必须调用的是自己的init,而不是父类的init
-- 不能被重写
-- 可以用于extension 来扩展控件的初始化操作

    // 便捷构造函数 (如果有初始化失败的情况,记得init? 可选的情况)
    convenience init?(name: String, age: Int) {
        // 年龄小于0不满足初始化条件
        // 直接返回nil,表示初始化失败
        if age < 0  {
            return nil
        }
        
        // 对象真正初始化
        self.init()
        
        // 赋新的值
        self.name = name
    }
析构函数

类似OC中的dealloc函数,可以在对象销毁前做一些事情。
-- 不可直接调用
-- 不可重载
-- 对象销毁前自动调用

    deinit {
        // 跟踪对象的销毁
        // 必须释放的资源
        
        /*
         -- 通知释放,不释放会造成内存泄露
         -- kvo释放,崩溃
         -- NSTimer
         -- CADisplay
         */
    }

KVC

-- 不能对private修饰的属性进行赋值。
-- oc中是全部裸露,与swift不同

KVO

kvo 是基于kvc的,都是OC运行时的概念,在swift中还需要做额外的工作,那就是将想要观测的对象标记为 dynamic。

import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

class MyClass: NSObject {
    dynamic var date = Date()
}

class MyClass1: NSObject {
    var date = Date()
}

class MyChildClass: MyClass1 {
    dynamic override var date: Date {
        get { return super.date }
        set { super.date = newValue }
    }
}

private var myContext = 0

class Class: NSObject {
    
    var myObject: MyClass!
    
    override init() {
        super.init()
        myObject = MyClass()
        print("初始化 MyClass,当前日期: \(myObject.date)")
        myObject.addObserver(self,
            forKeyPath: "date",
            options: .new,
            context: &myContext)

        delay(3) {
            self.myObject.date = Date()
        }
    }
    
    override func observeValue(forKeyPath keyPath: String?,
                            of object: Any?,
                               change: [NSKeyValueChangeKey : Any]?,
                              context: UnsafeMutableRawPointer?)
    {
        if let change = change, context == &myContext {
            let newDate = change[.newKey]
            print("日期发生变化 \(newDate)")
        }
    }
}

let obj = Class()

private & fileprivate & @objc

-- private 在swift3开始,private 就是真正的私有,只能在本类中访问(在extension或其他类中都不能访问)。
-- fileprivate 在当前文件中私有,别的文件不能访问此关键字修饰的属性和函数。
-- @objc 允许这个函数在运行时通过OC的消息机制被调用
-- open > public > interal > fileprivate > private

extension

-- 不能有属性
-- 不能重写父类方法

extension String {
    func myFrist() -> String? {
        let str = (self as NSString)
        if str.length == 0 {
            return nil
        }
        let f = str.substring(with: NSMakeRange(0, 1))
        return f
    }
}

错误处理

try?(有异常会返回nil) / try! (如果有异常就崩溃 )

let json = try? JSONSerialization.jsonObject(with: data! as Data, options: [])

捕获错误

do {
    let json =  try JSONSerialization.jsonObject(with: data! as Data, options: [])
} catch {
    print(error)
}

应用实战

一、runtime 获取属性
    class func propertyList() -> [String] {
        var count: UInt32 = 0
        var ptyList: [String] = []
        
        // 获取属性列表
        let list = class_copyPropertyList(self, &count)
        // 循环取出属性
        for i in 0..<Int(count) {
            
            // 用guard let 来优化  (?!)带来的解包问题
            // UnsafePointer<Int8>? -> Byte(8个字节)- Char ,C语言的字符串
            // 转换成String
            guard let pty = list?[i],
                let cName = property_getName(pty),
                let name = String(utf8String: cName) else {
                    continue
            }
            ptyList.append(name)
        }
        
        // 释放 C 语言对象
        free(list)
        print("属性数量\(count)")
        
        return ptyList
    }
二、循环引用

// 模拟加载数据的函数
func loadData(completion: @escaping () -> ()) {
    completion()
}

// weakSelf -> ViewController?
// OC的解决循环引用方法
weak var weakSelf = self
loadData {
    print(weakSelf?.view)
}

// Swift 推荐方法
// [weak self]  表示 {} 中所有self都是弱引用,需要注意解包
loadData { [weak self] in
    print(self?.view)
}
三、懒加载
    // 懒加载
    // 懒加载的代码只会在第一次调用的时候执行闭包
    // 如果label被置为nil,懒加载也不会再次执行
    /*
     1.延迟创建
     2.避免解包 ? 的烦恼
     */
    lazy var label: MyLabel = MyLabel()
    
    // 懒加载其实也是一个闭包
    // 上面的懒加载方式展开如下
    lazy var label = { () -> (MyLabel) in
        let l = MyLabel()
        return l
    }()
统计代码行数

在项目根目录下 以下命令

find . -name "*.swift" | xargs wc -l
上一篇下一篇

猜你喜欢

热点阅读