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
- 解决办法
- 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 -
- 文档注释 -> ///
- 单行注释 -> //
- 多行注释 -> /* */
- 分组注释 -> // MARK:-
访问权限
- swift中访问控制基于源文件,不是基于类
- internal -> 只要在本模块中可以访问(默认,所以可以不写)
- private -> 在当前文件中可以访问
- public -> 在其他模块中可以访问(也就是只要在项目中就可以使用它)
- swift中访问控制基于源文件,不是基于类
swift 2.2 语法 (下)的更多相关文章
- swift 2.2 语法 (中)
前言: 1.此文中的语法会根据Swift的升级变动而更新. 2.如果需要请移步 -> swift2.2 语法(上).swift 2.2语法(下) 函数 和C语言一样,swift也有函数,性质和我 ...
- swift 2.2 语法 (上)
前言: 1.此文中的语法会根据Swift的升级变动而更新. 2.如果需要请移步 -> swift2.2 语法(中).swift 2.2语法(下) Swift与OC中常见的区别 导入框架 OC: ...
- 利用Swift之协议语法实现页面间的传值功能
随着Swift 新开发语言的发布,又随着Xcode6.0.1的正式发布,利用swift编写iOS代码迫在眉睫,笔者在使用Objective-C开发近三年以来,对这种优雅的语法深感赞叹,下面我将对比式的 ...
- Swift之函数语法详解
函数 函数是用来完成特定任务的独立的代码块.你给一个函数起一个合适的名字,用来标识函数做什么,并且当函数需要执行的时候,这个名字会被“调用”. Swift 统一的函数语法足够灵活,可以用来表示任何函数 ...
- 吾八哥学Python(四):了解Python基础语法(下)
咱们接着上篇的语法学习,继续了解学习Python基础语法. 数据类型大体上把Python中的数据类型分为如下几类:Number(数字),String(字符串).List(列表).Dictionary( ...
- Swift基础之实现下拉变大和OC下拉变大上拉缩小Demo
Swift语言实现下拉变大效果:(上拉缩小效果随后研究......) 关键代码:方法一: self.automaticallyAdjustsScrollViewInsets = false; ...
- Swift初窥----语法进阶
缺省绑定(Optional Binding 自己主动置空) 通过在类型变量后,加上?,能够实现缺省绑定为nil var window: UIWindow? 就是说,假设不正确window赋值,则win ...
- swift 2.0 语法 函数
//: Playground - noun: a place where people can play import UIKit /*: 函数 * 格式 func 函数名称(形参名称1: 形参类型, ...
- swift 2.0 语法 可选类型
import UIKit /*: 可选类型(可以有值, 也可以没有值) * 在OC中我们可以给一个对象类型变量赋值为nil或者一个对象, 而在Swift中如果想给一个变量赋值为nil那么必须明确指定为 ...
随机推荐
- html/css基础篇——关于浏览器window、document、html、body高度的探究
首先说明本人所理解的这几个元素的计算 window高度应当是文档所在窗口的可视高度(没有包括浏览器的滚动条),计算方法document.documentElement.clientHeight doc ...
- SQL Server 2016的数据库范围内的配置
SQL Server 2016真的让人眼前一亮.几天前微软就提供了RCO(候选发布版)版本的下载.我已经围观了一圈RCO版本,其中一个最拽的功能是数据库范围内的配置(Database Scoped C ...
- chrome dev debug network 的timeline说明
在使用chrome的时候F12的开发者工具中有个network,其中对每个请求有个timeline的说明,当鼠标放上去会有下面的显示: 这里面的几个指标在说明在chrome使用文档有说明: 下面我用人 ...
- 【转载】GPU 加速下的图像处理
Instagram,Snapchat,Photoshop. 所有这些应用都是用来做图像处理的.图像处理可以简单到把一张照片转换为灰度图,也可以复杂到是分析一个视频,并在人群中找到某个特定的人.尽管这些 ...
- ES6笔记(3)-- 解构赋值
系列文章 -- ES6笔记系列 解构赋值,即对某种结构进行解析,然后将解析出来的值赋值给相关的变量,常见的有数组.对象.字符串的解构赋值等 一.数组的解构赋值 function ids() { ret ...
- EF基本操作增、删、查、改、分页,join……等
一.批量添加数据 static void Main(string[] args) { add(); add2(); Console.ReadKey(); } static void add() { D ...
- 30天C#基础巩固------this,base,string中的方法,StringBuilder性能
这里主要是记录下自己学习笔记,希望有个地方在以后可以看到自己走过的路. 关于之前多态的知识有一个口诀,很好理解里面的override和new,virtual关键字. "new则隐藏,over ...
- Learn Spring Framework(continue update...)
Part I. Overview of Spring Framework The Spring Framework is a lightweight(轻量级的) solution and a pote ...
- 【转】MyEclipse快捷键大全
常用快捷键 -------------------------------------MyEclipse 快捷键1(CTRL)------------------------------------- ...
- [小北De编程手记] : Lesson 05 玩转 xUnit.Net 之 从Assert谈UT框架实践
这一篇,本文会介绍一下基本的断言概念,但重点会放在企业级单元测试的相关功能上面.下面来跟大家分享一下xUnit.Net的断言,主要涉及到以下内容: 关于断言的概念 xUnit.Net常用的断言 关于单 ...