[Swift2.0系列]Defer/Guard 基础语法
1.Defer
Swift2.0中加入了defer
新语法声明。defer译为延缓、推迟之意。那么在Swift2.0中它将被应用于什么位置呢?比如,读取某目录下的文件内容并处理数据,你需要首先定位到文件目录,打开文件夹,读取文件内容以及处理数据,关闭文件以及文件夹。倘若一切顺利,只需按照设定好的程序流程走一轮即可;不过考虑事情要面面俱到,倘若中间某个环节失败,比如读取文件内容失败、处理数据失败等等,还需要进行一些后续收尾工作,即关闭文件或关闭文件夹(当然就算顺利执行,也是要关闭的)。
先谈谈defer
的基础语法,声明方式如下:
defer{ // 做一些事情}
可以看到声明方式非常简单,defer
关键字打头,紧跟{}
程序块,大括号中添加延迟处理代码。平常应用方式如下:
func doSomethingWithDefer(){
// 1
openDirectory()
// 2
defer{closeDirectory()}
// 3
openFile()
// 4
defer{closeFile()}
// 做其他杂七杂八事情...
}
分析代码:
- 定位到目录并打开指定文件夹,倘若打开文件夹失败则结束函数。
- 主要到
defer
的用法,这条语句并不会马上执行,而是被推入栈中,直到函数结束时才再次被调用。 - 打开文件,倘若失败则结束函数。
defer
内容关闭文件,这条语句一样不会被马上执行,而是推入栈中,此时它位于defer{closeDirectory()}
语句的上方,直到函数结束时才再次被调用。
倘若一切都顺利,函数运行到最后了,开始从栈中依次弹出方才推入的defer
语句,首先是closeFile()
,其次是closeDirectory()
。确实当我们处理完文件,需要先关闭文件,再关闭文件夹。
现在试想一种情况,我们已经打开文件夹,并且推closeDirectory()
到栈中,执行第三步openFile()
操作的时候出错了!那么下面所有操作就无法进行下去,结束整个函数了!前文说到函数结束时开始执行defer
栈中的内容,关闭文件夹。会有人说怎么不关闭文件,拜托失败了就意味着文件没被打开,何来关闭一说。
最后必须说下defer
的作用域,这点灰常重要。
注意作用域,其次是调用顺序——即一个作用域结束,该作用域中的defer语句自下而上调用。
func lookforSomething(name:String) throws{
//这里是作用域1 整个函数作用域
print("1-1")
if name == ""{
//这里是作用域2 if的作用域
print("2-1")
defer{
print("2-2")
}
print("2-3")
}
print("1-2")
defer{
print("1-3")
}
print("1-4")
if name == "hello"{
//作用域3
print("3-1")
defer{
print("3-2")
}
print("3-3")
defer{
print("3-4")
}
}
}
//有兴趣的看看依次输出什么
//try! lookforSomething("")
//调出 debug Area 快捷键 shift+ command + y
try! lookforSomething("hello")
其实先前有个地方说的不准确,并不是函数结束时开始执行defer
栈推出操作,而是每当一个作用域结束就进行该作用域defer
执行。
2.Guard
guard
有控制、警戒之意,语法简单,只需两个示例代码即可明白。
示例一:
// 这里使用if 和 guard进行对比 你会懂的更多
if age < 13 {
return //当年龄小于13时 程序返回 不进行之后的操作
}
用guard
改写
guard age >= 13 else{
return
}
可以看到代码的意思是保证(guard)age值大于等于13 否则(else)返回,不执行下面程序。
guard充当了警卫员一职,保证条件满足情况下,才会让你通过,否则只能else让你返回了!切记else中一定需要有返回的语句,比如return、continue、break、throw这种提早退出的关键字!!
实例二:
关于if-let
解包,我们一般这么写:
func greet(person: [String: String]) {
if let name = person["name"]{
print("Hello \(name)!")//名字存在
if let location = person["location"]{
print("I hope the weather is nice in \(location).")
}else {
print("I hope the weather is nice near you.")
return
}
}else {
return
}
}
greet(["name": "John"])
// prints "Hello John!"
// prints "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
// prints "Hello Jane!"
// prints "I hope the weather is nice in Cupertino."
使用guard
改写之后:
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)!")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(["name": "John"])
// prints "Hello John!"
// prints "I hope the weather is nice near you."
greet(["name": "Jane", "location": "Cupertino"])
// prints "Hello Jane!"
// prints "I hope the weather is nice in Cupertino."
如此改法有点有如下几个方面:
- 代码清爽直观。
- 不必再if套if,会混淆你的逻辑。
if let name = person["name"]{}
其中name的作用域仅局限于紧随的大括号中,而guard let name = person["name"]
范围更广!
实例三:
出自Thinking in Swift, Part 2: map those arrays一文中例子,感觉不出,供大家学习。代码简单易懂,又不乏知识点。
class ListItem {
var icon: UIImage?
var title: String = ""
var url: NSURL!
static func listItemsFromJSONData(jsonData: NSData?) -> [ListItem] {
guard let nonNilJsonData = jsonData,
let json = try? NSJSONSerialization.JSONObjectWithData(nonNilJsonData, options: []),
let jsonItems = json as? Array<NSDictionary>
else {
// If we failed to unserialize the JSON or that JSON wasn't an NSArray,
// then bail early with an empty array
return []
}
var items = [ListItem]()
for itemDesc in jsonItems {
let item = ListItem()
if let icon = itemDesc["icon"] as? String {
item.icon = UIImage(named: icon)
}
if let title = itemDesc["title"] as? String {
item.title = title
}
if let urlString = itemDesc["url"] as? String, let url = NSURL(string: urlString) {
item.url = url
}
items.append(item)
}
return items
}
}
实例四(2015.12.07新增):
enum CircleAreaCalculationError: ErrorType {
case RadiusNotSpecified
case RadiusUnvalid
}
// 尽管还没有成为鞭尸金字塔 但是也快了
func calculateCirlceArea(radius:Double?) throws -> Double {
if let radius = radius {
if radius > 0 {
return radius*radius*M_PI
} else {
throw CircleAreaCalculationError.RadiusUnvalid
}
} else {
throw CircleAreaCalculationError.RadiusNotSpecified
}
}
使用guard修改之后:
enum CircleAreaCalculationError: ErrorType {
case RadiusNotSpecified
case RadiusUnvalid
}
func calculateCirleArea(radius:Double?) throws -> Double {
guard let radius = radius else {
throw CircleAreaCalculationError.RadiusNotSpecified
}
guard radius > 0 else {
throw CircleAreaCalculationError.RadiusUnvalid
}
return radius*radius*M_PI
}
[Swift2.0系列]Defer/Guard 基础语法的更多相关文章
- php从入门到放弃系列-02.php基础语法
php从入门到放弃系列-02.php基础语法 一.学习语法,从hello world开始 PHP(全称:PHP:Hypertext Preprocessor,即"PHP:超文本预处理器&qu ...
- MYSQL从入门到放弃系列:mysql基础语法
Mysql基本语法 启动MySQL net start mysql 连接与断开服务器 mysql -h 地址 -P 端口 -u 用户名 -p 密码 跳过权限验证登录MySQL mysqld --ski ...
- swift3.0基础语法
swift 3.0 基础语法 目录 01-变量和常量 02-运算符 03-可选项 04-条件语句 05-循环 06-字符串 07-元组 08-数组 09-字典 10-对象和类 11-枚举 12-属性 ...
- openresty开发系列15--lua基础语法4表table和运算符
openresty开发系列15--lua基础语法4表table和运算符 lua中的表table 一)table (表)Table 类型实现了一种抽象的"关联数组".即可用作数组,也 ...
- openresty开发系列14--lua基础语法3函数
openresty开发系列14--lua基础语法3函数 一)function (函数) 有名函数: optional_function_scope function function_name( ar ...
- openresty开发系列13--lua基础语法2常用数据类型介绍
openresty开发系列13--lua基础语法2常用数据类型介绍 一)boolean(布尔)布尔类型,可选值 true/false: Lua 中 nil 和 false 为"假" ...
- emmet 系列(1)基础语法
emmet 系列(1)基础语法 emmet 是一个能显著提升开发html和css开发效率的web开发者工具 emmet基本上目前已知的编辑器都有相应的插件,各个编辑器的emmet插件的下载地址:点我下 ...
- swift3.0基础语法(2)
变量/常量,元组声明 var aaa = 0;//声明变量aaa 首次赋值时自动解析为Int类型 var aaa:Int = 0;//声明Int类型变量aaa let aaa = 0;//声明常量aa ...
- Scala入门系列(一):基础语法
Scala基础语法 Scala与JAVA的关系 Scala是基于Java虚拟机,也就是JVM的一门编程语言,所有Scala的代码都需要经过编译为字节码,然后交由Java虚拟机来运行. 所以Scala和 ...
随机推荐
- HTML标签的默认样式
body 有默认的内外边距(margin:0;padding:0); p 有默认的外边距(margin:0;)
- Java 如何得到 JVM 虚拟机的 System Properties
Java 6 jps 命令得到进程号 jinfo -sysprops <PID> > sysprops.txt 打开 sysprops.txt 就可以查找 Language Time ...
- JavaScript设计模式与开发实践 - 策略模式
引言 本文摘自<JavaScript设计模式与开发实践> 在现实中,很多时候也有多种途径到达同一个目的地.比如我们要去某个地方旅游,可以根据具体的实际情况来选择出行的线路. 如果没有时间但 ...
- 【bzoj1023】仙人掌图
[bzoj1023]仙人掌图 题意 给一棵仙人掌,求直径. \(n\leq 100000\) 分析 分析1:[Tarjan]+[环处理+单调队列优化线性dp]+[树形dp] 分开两种情况处理: ①环: ...
- Android Service与Thread的区别
Android Service,后台,Android的后台就是指,它的运行是完全不依赖UI的.即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行.比如说一些应用程序 ...
- ajax正确的简单封装“姿势”
window.meng = window.meng || {}; (function ($) { function getAjaxDate(url, apikey) { var datas; $.aj ...
- jmeter笔记5
性能测试是任何分布式或Web应用程序测试计划的重要组成部分.在计划和开发周期中进行性能评价,可以保证交付给客户的应用程序满足客户对于高负载.可用性和可伸缩性的要求.提前确定软件的负载限制可以为适当地进 ...
- CentOS中输入yum报错:sudo: unable to execute /bin/yum: No such file or directory
今天尝试更新了下虚拟机CentOS中的python版本后. 运行“yum”命令,就报错:“sudo: unable to execute /bin/yum: No such file or direc ...
- VirtualBox – Error In supR3HardenedWinReSpawn 问题解决办法
转:http://chenpeng.info/html/3510---------VirtualBox – Error In supR3HardenedWinReSpawn---------<h ...
- hdu---(1800)Flying to the Mars(trie树)
Flying to the Mars Time Limit: 5000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...