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那么必须明确指定为 ...
随机推荐
- 在SQL Server里为什么我们需要更新锁
今天我想讲解一个特别的问题,在我每次讲解SQL Server里的锁和阻塞(Locking & Blocking)都会碰到的问题:在SQL Server里,为什么我们需要更新锁?在我们讲解具体需 ...
- 在SQL Server里禁用聚集索引——真的好么?
有人问了我一个最有意思的问题:“你能禁用聚集索引么?” 对这个问题,我先是吓了一跳,因为我从未想过禁用聚集索引,因为聚集索引代表表数据,对这个最有趣问题,我立即答道:“我认为可以,但是...” 好吧, ...
- 关于WEB Service&WCF&WebApi实现身份验证之WCF篇(2)
因前段时间工作变动(换了新工作)及工作较忙暂时中断了该系列文章,今天难得有点空闲时间,就继续总结WCF身份验证的其它方法.前面总结了三种方法(详见:关于WEB Service&WCF& ...
- 使用Tuple来实现多个Model传送至视图
前面Insus.NET实现过<使用ViewModel来实现多个Model传送至视图>http://www.cnblogs.com/insus/p/5594134.html 和<使用E ...
- 反射(Reflection)的SetValue遇上DBNULL转换为string
有网友回馈说提供的代码有bug.你可以从这个链接下载得到:http://www.cnblogs.com/insus/p/3384472.html 其中有一个Utility,它是把DataTable转换 ...
- Nancy 学习-自宿主 继续跨平台
Nancy简介 Nancy是一个轻量级的独立的框架,下面是官网的一些介绍: Nancy 是一个轻量级用于构建基于 HTTP 的 Web 服务,基于 .NET 和 Mono 平台,框架的目标是保持尽可能 ...
- 基于吉日嘎拉的通用权限管理Webform版老界面bug修复
虽然弄了新界面<基于吉日嘎底层架构的通用权限管理Web端UI更新:参考DTcms后台界面>,但老界面的一点菜单显示的问题还是让我这种强迫症揪心,终于今晚可以美美的睡觉了. 老代码用了Ses ...
- csharp:using OpenXml SDK 2.0 and ClosedXML read excel file
https://openxmlexporttoexcel.codeplex.com/ http://referencesource.microsoft.com/ 引用: using System; u ...
- NYOJ 737---石子归并(GarsiaWachs算法)
原题链接 描述 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆.合并的过程只能每次将相邻的两堆石子堆成一堆,每次合并花费的代价为这两堆石子的和,经过N-1次合并后成为一堆.求 ...
- 我的css笔记
1.css的使用方法 内嵌样式 <p style="font-size:20pt;color:red;">这个Style定义<p> <!--里面的文字 ...