swift 2.2 语法(下)

前言:
1.此文中的语法会根据Swift的升级变动而更新。
2.如果需要请移步 -> swift2.2 语法(上)swift 2.2语法(中)

类的析构函数

  • swift会自动释放不需要的实例来达到释放资源的目的

    • swift通过自动引用计数(ARC)管理内存

    • 当引用计数为0的时候,系统会自动调用析构函数(析构函数无法手动调用)

    • 通常在析构函数内释放一些资源(移除通知、释放不需要对象等)

    • 格式:


      deinit {
          需要执行的操作
      }
      
      
  • 这个比较好理解,就直接上代码了

class person: NSObject {

    //  KVC方式下,对象、结构体类型必须是可选类型,否则无法转换
    var name : String?
    
    //  自定义构造函数,覆盖init:函数
    init(dict : [String : NSObject]) {
        
        //  必须先初始化对象
        super.init()
        
        //  调用对象的KVC方法
        setValuesForKeysWithDictionary(dict)
    }
    
    deinit {
        print("移除通知")
        print("释放各种资源")
    }
}

//  创建person对象
var ps : person? = person(dict:["name" : "laoWang"])
ps = nil    //  当赋值为nil时自动引用计数为0,系统将会调用deinit对资源进行释放
    

自动引用计数

  • swift也是采用自动引用计数来管理内存

    • 当有一个强引用指向某个对象时,这个对象的引用计数会+1
    • 如果强引用消失,引用计数会-1
    • 但引用计数为0的时候,这个对象就会被系统销毁
  • 循环引用

    • 一般情况下,ARC会自动帮我们管理内存,但是开发中经常会会出现循环引用的问题,这样就造成资源始终无法释放的现象
    • 循环引用如图:


    
    class Person {
        var dog : Dog?
    
        deinit {
            print("释放person")
        }
    }
    
    class Dog {
        var master : Person?
    
        deinit {
            print("释放Dog")
        }
    }
    
    //  创建对象
    var ps : Person? = Person()
    var d : Dog? = Dog()
    
    //  循环引用
    ps?.dog = d
    d?.master = ps
    
    //  释放资源失败原因:因为person内有个属性强引用着Dog,而Dog内也有个强引用引用着Person,造成了循环引用,所以即使将ps和d赋值为nil也无法释放对象
    ps = nil
    d = nil
    
    
循环引用.png
- 解决办法
    - swift提供了2中方法来解决循环引用的问题
        - 使用weak:这个关键字和OC的__weak一样都是弱引用,当指向的对象呗销毁的时候,会自动将指针指向nil
        - 使用unowned:和OC中的__unsafe_unretained相似,当对象销毁时,指针依然指向原来的位置(比较危险,容易引起野指针错误)
        <br><br>
        
        ```
        class Person {
            //  声明dog为弱引用
            weak var dog : Dog?

            deinit {
                print("释放person")
            }
        }

        class Dog {
            var master : Person?

            deinit {
                print("释放Dog")
            }
        }

        //  创建对象
        var ps : Person? = Person()
        var d : Dog? = Dog()

        //  循环引用
        ps?.dog = d
        d?.master = ps

        //  person和dog对象被释放
        ps = nil
        d = nil
        
        ```

可选链

  • 调用的目标可能为nil,如果可选的目标有值,就会调用成功;如果可选目标为nil,调用会返回nil
  • 多次调用链接在一起就形成一个调用链,任何一个节点为nil,整个链就会失效
  • 可选链使用
    • 在可选类型后面+一个?号,可以定义一个可选链;有点像在可选值后放个!号来强制解包得到值

      • 当可选值为空的时候,可选链就会失效
      • 一般的强制解析会引起运行错误
    • 因为可选链的结果可能为nil,所以它返回的值是个可选类型

      • 可以通过判断返回的参数是否有值来确定是否成功调用(返回nil说明失败)


      class Person1 {
      
          var name : String
          var dog : Dog?
      
          init(name : String) {
      
              self.name = name
          }
      
      }
      
      class Dog {
      
          var ball : Ball?
      
          func yesOrNo() {
              print("YES,可选类型有值") //  调用成功
          }
      }
      
      class Ball {
      
          var price : Double = 0.0
      
      }
      
      //  创建对象并设置相互的关联性
      let ps = Person1(name: "LiSi")
      let d = Dog()
      let ball = Ball()
      ball.price = 300.0
      
      //  李四拥有一条狗
      ps.dog = d
      //  狗有个球
      d.ball = ball
      
      //  获取狗的球的价格
      let price = ps.dog?.ball?.price
      print(price)    //  结果:300.0
      
      //  给狗一个新的球
      ps.dog?.ball = Ball()
      //  如果返回值有值就会继续执行下面这句,如果nil就不会执行
      ps.dog?.yesOrNo()
      
      

协议

  • 格式:
protocol 协议名 {
    协议方法
}

  • 遵守协议格式
class 类名 : 类的父类, 协议名,协议名 {
    
}

//  比如
class ViewController: UIViewController, UITableViewDelegate {
    
}

  • 协议使用

//  定义
protocol testProtocol {
    //  协议方法
    func test1()
    func test2()
}

//  使用(swift中默认情况下所有的协议方法都必须实现,不然会报错)
class Person : testProtocol {
    var name : String?
    
    //  实现协议方法
    func test1() {
        print("test1")
    }
    
    func test2() {
        print("test2")
    }
}

  • 协议继承
//  定义
protocol testProtocol {
    //  协议方法
    func test1()
    func test2()
}

protocol test2Protocol : testProtocol {
    //  协议方法
    func test3()
}

  • 代理设计模式(根据协议可以继承的特性,我们将其用于代理设计模式)
//  定义
protocol testProtocol {
    //  协议方法
    func test1()

}

//  使用(swift中默认情况下所有的协议方法都必须实现,不然会报错)
class Person {
    
    //  定义delegate属性
    var delegate : testProtocol
    
    //  自定义构造函数
    init(delegate : testProtocol) {
        
        self.delegate = delegate
    }
    
    //  方法
    func personTest() {
        
        delegate.test1()
    }

}

class Dog : testProtocol {
    
    func test1() {
        print("调用test1")    //  结果:调用test1
    }
}

//  设置代理
let p = Person(delegate: Dog())
//  实现代理方法
p.personTest()

  • 协议方法不需要全部实现的解决方法
//  如果不是每个协议方法都必须实现只需这样写
@objc

protocol testProtocol {
    //  协议方法
    optional func test1()

}


闭包

  • 闭包类似于OC中的Block

    • swift的闭包是特殊的函数,OC的Block是匿名函数
    • 和block一样,闭包也经常用于回调
  • 闭包的格式

(形参列表)->(返回值)
    
  • 来个简易网络请求举例吧,用block做对比
//  block形式

- (void)downloadData:(void (^)())block
{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        
        NSLog(@"下载数据:%@", [NSThread currentThread]);
        
        dispatch_sync(dispatch_get_main_queue(), ^{
            //  调用block
            block();
        });
    });
}
   
    
- (void)test
{
    [self downloadData:^{
        NSLog(@"block块: %@", [NSThread currentThread]);
    }];
}


//  闭包形式

func downloadData(block : () -> ()) {
    
    dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
        
        print("下载数据:\(NSThread.currentThread())")
        
        dispatch_sync(dispatch_get_main_queue(), { () -> Void in
            
            block()
        })
    }
}

func test() {
    
    downloadData { () -> () in
        print("block块:\(NSThread.currentThread())")
    }
}

  • 闭包简写

    • 当闭包没有参数、返回值的时候, in和.in之前的内容可以省略不写


    downloadData ({
        print("block块:\(NSThread.currentThread())")
    })
    
    
    • 尾随闭包

      • 如果闭包是函数的最后一个参数,可以将闭包写在()后面


      downloadData(){ () -> () in
          print("block块:\(NSThread.currentThread())")
      }
      
      
      • 函数只有一个参数,并且这个参数是闭包,那()可以忽略


      downloadData { () -> () in
          print("block块:\(NSThread.currentThread())")
      }
      
      

闭包的循环引用

  • 如果在函数中对闭包进行了强引用,会造成循环引用
  • 这边我们先来搞个循环引用的例子
class download : NSObject {
    
    //  定义变量来强引用block
    var block : (()->())?
    
    func downloadData(block : ()->()) {
        dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
                print("下载数据:\(NSThread.currentThread())")
            dispatch_sync(dispatch_get_main_queue(), { () -> Void in
                
                block()
            })
            //  制造循环引用
            self.block = block
        }
        
    }
    
    deinit {
        print("deinit")
    }
}

var d : download? = download()

d?.downloadData { () -> () in
    print("调")
}

d = nil

  • 循环引用解决方法

    • 方法一:最先想到的肯定是使用weak修饰当前控制器,但是self可能有值也可能为nil,所以weakself是可选类型,在使用的时候需要对它进行强制解包操作(这边可以直接解包,因为如果控制器不存在,就不可能调用函数)


    //  且必须是变量,不能是常量
    weak var weakSelf = self
    
    
    • 方法二:使用unowned关键字,缺点就是容易造成野指针的现象,因为即使对象被释放,它的指针还是指向原来的位置,不会自动指向nil


    unowned var unSelf = self
    
    

懒加载

  • 懒加载就是在我们需要使用的时候才会真正加载到内存中的一种编程思想
  • swift中使用 'lazy' 关键字来实现懒加载
  • 懒加载本质就是在第一次使用的时候执行闭包,把闭包的返回值赋值给属性,而且只会赋值一次
  • 格式:
lazy var 变量名 : 类型 = {   
    
    创建代码

}()

  • 懒加载使用
lazy var test : [Int] = {

    () -> [Int] in 
    return 27

}()


异常处理(抛异常提示)

  • 开发中,经常会出现错误,swift设计的时候就已经考虑到这方面,尽可能多地帮我们明确错误原因
  • 在swift中,任何一个遵守ErrorType protocol的类型,都可以用来描述错误
  • ErrorType是个空protocol(协议),它功能很单一,就是用来告诉编译器,某个类型用来表示错误
  • 我们常会定义一个枚举(enum)来确定各种可能出现的错误
  • 来简单模拟下异常情况
//  假定这个方法我们不知道他的实现方式,如果不错任何处理,那么就很难猜中需要传的值
func test(name : String) -> String? {
    
    guard name == "laoWang" else {
        return nil
    }
    
    guard name == "laoLi" else {
        return nil
    }
    
    return "true"
}

test("12")  //  结果为nil

  • 使用抛异常的方式来尽可能告诉使用者错误原因
//  定义异常情况枚举
enum error : ErrorType {
    
    case errorNameNotForLaoWangOrLaoLi

}

//  假定这个方法我们不知道他的实现方式,如果不错任何处理,那么就很难猜中需要传的值
func test(name : String) throws -> String {
    
    guard name == "LaoWang" else {

        throw error.errorNameNotForLaoWangOrLaoLi
        
    }
    
    guard name == "LaoLi" else {
        
        throw error.errorNameNotForLaoWangOrLaoLi
    }
    
    return "true"
}

//  处理方法一 try!:告诉系统调用没有异常,如果出现异常,程序会崩溃

try! test("lao") //  结果 fatal error: 'try!' expression unexpectedly raised an error: error.errorNameNotForLaoWangOrLaoLi: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-700.1.101.15/src/swift/stdlib/public/core/ErrorType.swift, line 50

//  处理方法二 try? 出现异常返回nil,没有异常返回对应的值(返回的结果是个可选类型)

let result = try? test("hh")    //  结果 nil

//  处理方法三 try 需要手动处理异常
do {
    let result = try test("hh")
} catch {
    print(error)    //  结果 errorNameNotForLaoWangOrLaoLi
}


补充

  • 注释

    • 分组注释 -> // MARK:-
      • swift中不可以再使用 #pragma mark -
    • 文档注释 -> ///
    • 单行注释 -> //
    • 多行注释 -> /* */
  • 访问权限

    • swift中访问控制基于源文件,不是基于类
      • internal -> 只要在本模块中可以访问(默认,所以可以不写)
      • private -> 在当前文件中可以访问
      • public -> 在其他模块中可以访问(也就是只要在项目中就可以使用它)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容