Swift英语语法大全求解

Swift 学习之二十一:?和 !(详解) - CSDN博客
Swift 学习之二十一:?和 !(详解)
新更新的内容请移步阅读:
Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值,
也就是说变量不会有默认值,所以要求使用变量之前必须要对其初始化
。如果在使用变量之前不进行初始化就会报错:
var stringValue : String
//error: variable 'stringValue' used before being initialized
//let hashValue = stringValue.hashValue
let hashValue = stringValue.hashValue
出错的原因就是在使用stringValue这个变量之前,没有初始化这个变量,也就是这个变量根本就没有得到内存,
这时就会出错。
那么我们可以使用optional类型,后面跟一个?就是了。
// 这就是optional, strValue自动得到默认值:nil
// 这个nil跟Objective-C中的nil不同,不是指针,而是表示值不存在。
var strValue: String?
// 判断optional是否有值
if strValue {
// do what you need to do here
文档中有提到说,在使用Optional值的时候需要在具体的操作,比如调用方法、属性、下标索引等前面需要加上一个?,如果是nil值(不存在值),也就是Optional.None,会跳过后面的操作不执行,如果有值,就是Optional.Some可能就会拆包(unwrap),然后对拆包后的值执行后面的操作,来保证执行这个操作的安全性,比如Optional
// optional binding
// 如果strValue == nil, 那么结果就是nil,不会调用String的hasValue
// 如果strValue != nil, 就返回strValue对应的hashValue值并赋值给常量hashValue
if let hashValue = strValue?.hashValue {
// do something if neccessary
在写协议(protocol)时,对于可选代理方法,也需要在调用时在函数名后跟着?,如:
// @objc 是用于处理Swift与OC之间的转换的,由于@optional是OC中的关键字,
// 所以在protocol之前需要添加上@objc。
@objc protocol HttpRequestDelegate {
// @optional 说明这个代理方法是可选方法,
// 那么在调用的时候,需要这样调用:delegate?.requestFinished?(self, downloadData)
// 其中delegate?是因为delegate也是optional的
@optional func requestFinished(request: HttpRequest!, downloadData: NSMutableData!)
// other funcs ...
var delegate: HttpRequestDelegate?
var downloadData = NSMutableData()
delegate.requestFinished(self, downloadData)
当然我们也可以使用!来强制拆包,这是我们在保证有值的情况下才会这么用:
var strValue: String?
strValue = &1234&
let integer = strValue!.toInt()
// 更安全的写法是
if strValue {
let integer = strValue!.toInt()
隐式强拆包类型:
使用!来声明变量,会成为隐式强拆包可选类型,这表示这个类型永远不会出现nil的情况,但一旦出来,
在调用时就会崩溃。
// Implicitly Unwrapped Optionals
// 使用这种方式声明的话,在调用时不需要使用?或!来说明。
var myLabel: UILabel!
myLabel = UILabel(frame: CGRectMake(10, 100, 300, 10))
myLabel.text = &label&
通常在什么情况下才会使用optional类型呢?
(1)当我们需要声明这样一个变量,变量在设计初始化函数中没有进行初始化时,就需要声明这个变量为optional类型。因为变量在使用前必须先
& & & & 声明,并且在设计初始化函数中进行初始化。比如我们在viewDidLoad函数中才进行初始化的控件(类成员),就需要声明为optional且必须是var声明,
& & & &因为let声明的常量只能是在初始化函数中进行初始化。
(2)当我们不知道是否会有值的时候,这个变量可以声明为optional,比如代理,我们并没有要求必须传代理过来,那么就需要声明为optional。
(3)作为函数参数时,如果这个参数可以没有值,那么就使用optional类型,比如传代理的时候,通常就是可选的,可以设置为nil
......暂时只想到这些,任何人都可以继续往下补充!
本文已收录于以下专栏:
相关文章推荐
img border=0 src=&imageAction.do&&webwork自生成验证码图片ResultTyp ImageResult.classpackage com.test.randomi...
原文出自:标哥的技术博客
前言最近还是有不少朋友老问Swift版的自动计算行高怎么做,大家使用SnapKit来自动布局时,都希望能够自动地计算出行高,不用每次都自己去算一篇。本篇介绍笔者所开源的基于S...
转载:http://blog.csdn.net/gf771115/article/details/
Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量...
转自:.cn/s/blog_7ux3v.html
Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量...
swift中?和!的区别
知乎上某人的ios面试题1.什么是arc?(arc是为了解决什么问题诞生的?)首先解释ARC: automatic reference counting自动引用计数。
ARC几个要点:
扩展(extension)
扩展是向一个已有的类、结构体或枚举类型添加新的功能。在swift中扩展是没有名字的,
但在Objective-C中Category是有名字的,而且只能扩展类(类别)
Optional也是Objective-C没有的数据类型,是苹果引入到Swift语言中的全新类型,它的特点就和它的名字一样:可以有值,也可以没有值,当它没有值时,就是nil。此外,Swift的nil也...
Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值,
也就是说变量不会有默认值,所以要求使用变量之前必须要对其初始化
。如果在使用变量之前不进行初始化就...
充满向往的尝试Swift 的 String的用法,然后,就各种蛋疼。。。这就是我用的感受  注意: 此处为iOS 9代码,iOS 10可能会不适配
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)详解swift和OC以及C语言的混编(不看后悔!)
语言出来后,可能新的项目直接使用swift来开发,但可能在过程中会遇到一些情况,某些已用OC写好的类或封装好的模块,不想再在swift 中再写一次,或者有一些第三方使用OC写的,没有swift版本,怎么办?那就使用混编。这个在IOS8后是允许的.
先简单的入手,先研究在同一个工程目录下混合使用的情况.这里主要介绍swift类中调用OC方法和swift类中调用C函数以及OC类中调用swift的函数这三种类型的混编.另外,小编也是边研究边尝试才做出结果的,因此命名并非规范命名,大家就不要纠结命名问题了.小编这里使用swift创建的工程,工程名为SwiftTest.(其实用OC创建工程也大同小异)
1.创建swift工程,工程名SwiftTest
2.创建一个swift的类
3.创建一个OC的类
4.创建两个C语言的类(一个包含头文件,另一个不包含头文件)
创建结果如下图:
接下来,先说一下,创建过程中的情况:
1.创建swift类,可以用快捷键 command+n
创建swift类的时候有两种方式,如下图
注意:选绿框中这两个地方都可以创建swift类,语言选Swift,然后注意,一定要继承于NSObject,这个非常重要,否则在OC中不做修改调不到这个类的方法,就比较麻烦了,还是一步到位,继承NSObject吧.另外还要注意红框的位置,创建时一定要手动选择红框中这一项(iOS的Source),别用默认的,默认的是(OS X 的Source),后边会讲为什么.
然后创建成功就是这样的了
这个是选择iOS 的 Source ,然后用Cocoa Touch Class 创建的,如果是用Swift File 创建的类,那上面图片的绿框中就是 import Foundation 了,这个还好,影响不大(个人建议用Cocoa Touch Class,因为它导入的UIKit是包含Foundation的,当然还是看你的喜好了).但是如果你用的是默认的 OS X 的 Source,然后用Cocoa Class创建(Cocoa Touch Class他俩图标是一样的,不看名字还真没看出来他俩有区别),那上面绿框中就是import cocoa,并且混编的时候会报错.我上两个图(左边默认,右边选择后的),大家就明白为什么会范这种错误了
2.创建OC类
这个不说怎么创建了,都会吧!但有一点得说,那就是,在swift工程中,不再使用头文件和.m文件的方式了。所以也不需要使用import &&来导入头文件。那swift 如何能访问到OC的类声明呢?其实,swift也是需要使用头文件进行访问的,只不过不再需要使用显式的方式使用import进行导入。有两种方式来实现这个头文件的生成。
方式一:在一个全新的Swift,利用第一次新建提示的方式自动添加桥接头文件。
这个是在swift项目中,创建其他语言类的时候(OC,C等),会提示你添加一个桥接头文件,如图
然后点击蓝色那个按钮,就会生成一个桥接头文件,这个文件的格式为&你的工程名字-Bridging-Header.h&,如图中绿框所示
有的可能是xcode配置问题,没有提示,那也可以自己创建一个,格式得按照以上的格式,但还有一种方式,不仅能创建还可以改变这个格式,取一个自己喜欢的文件名,但需要修改一些配置.
方式二:新建一个头文件,名为:JeckHeader.h
在targets-&build settings -&Object-C Bridging Header 位置设为Swift/JeckHeader.h,如下图所示,这个头文件也就是桥接头文件,代码一会儿再说.
3.创建C语言类
这里有一个需要注意的地方,创建C语言的类,和创建OC类差不多,如图选择C File 创建就好了
但是,点击Next会出现下图界面,看到那个蓝色的&&&没有,加上&,创建的C语言的类,类似OC,会有一组两个文件,一个是.c文件一个是.h文件,.h文件就是这个C语言的头文件,如果取消&,创建的C语言的类是没有头文件的.为方便学习,我把含头文件的和不含头文件的类,都分别创建了,后边代码中会分别介绍他们怎么用.
到这里,我们的准备工作做完了,接下来,结合代码,来研究一下,swift调用OC里的方法,swift调用C语言的函数,OC调用swift函数,OC调用C语言的函数这几种情况,如果前边的准备工作做好了,那接下来会很容易理解.
然后结合代码讲解比较直观:
SwiftClass.swift 类中的代码,这里边只是添加了一个函数,OC的类会调用这个方法
import UIKit
class SwiftClass: NSObject {
func sayHello(name:String) -& String {
let greeting = &Hello& + name + &!&
return greeting
OC的.m文件,这里实现了两个方法并定义了一个C语言的函数,为了方便对比,方法里实现了block,在这个类中演示:OC调用swift类中的方法
#import &OCClass.h&
#import &SwiftTest-swift.h&//细心的朋友一定注意到了,项目文件中并没有这个头文件,但实际上项目中是有的,你也可以用command+鼠标左键跳进去查看,是隐藏的,如果你是按照我前边的讲的创建的swift文件,那你在这里是可以导入这个头文件的,格式为&工程名-swift.h&,它就是项目中所有的swift类的头文件.
@implementation OCClass
-(void)desc22{
//声明block
int (^p)(int, int);
//把函数赋值给block
p = ^(int a, int b){
return a +
int result = p(10,40);
NSLog(@&swift调用OC方法输出result:%d\n&,result);
//OC中调用swift函数
SwiftClass *sc = [[SwiftClass alloc] init];//创建swift对象
NSString *str =[sc sayHello:@&jeck&];//用swift的对象调用自己的函数(方法)
NSLog(@&OC中调用swift函数输出 %@&,str);
//定义函数
int sum2(int a, int b){
return a +
-(void)desc2{
//2.声明block
int(^p)(int, int);
//3.把函数赋值给block
//p = sum2;
p = ^(int a, int b){
return a +
int result = p(10,40);
printf(&swift调用OC方法输出result:%d\n&,result);
OCClass.h OC的头文件,声明了.m中的两个方法和一个C语言函数,为了能被外界调用到
@interface OCClass : NSObject
int sum2(int a, int b);
-(void)desc22;
-(void)desc2;
C语言类的.c文件,定义了两个函数
#include &CClass.h&
//1.定义函数
int sum3(int a, int b)
return a+b;
void desc3(){
//2.声明函数指针
int (*p)(int, int);
//3.函数指针指向函数
int result = p(10,10);
printf(&swift调用有头文件的C函数输出:%d\n&,result);
C语言类的头文件,声明了两个函数,作用同OC,方便外界调用
#ifndef CClass_h
#define CClass_h
//和OC中类似,在C的头文件中声明两个函数
int sum3(int a, int b);
void desc3();
#endif /* CClass_h */
CClassNo.c
这个类是没有头文件的的类,实现了两个函数
//1.定义函数
int sum1(int a, int b)
return a+b;
void desc1(){
//2.声明函数指针
int (*p)(int, int);
//3.函数指针指向函数
int result = p(10,20);
printf(&swift调用C函数输出result:%d\n&,result);
//桥接头文件SwiftTest-Bridging-Header.h
#import &CClass.h&
//导入OC类
#import &OCClass.h&
//声明没有头文件的C语言类中的函数
void desc1();
int sum1(int a, int b);
ViewController.swift
这个是创建工程的时候,系统自带的那个swift类,在这里演示:swift调用OC方法,swift调用C方法
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//swift调用oc方法
let funOC = OCClass()
funOC.desc2()
funOC.desc22()
let funOCClass2 = sum2(10, 1)
print(&swift调用OC类中的C函数输出:\(funOCClass2)&)
//swift调用c函数(无头文件)
let funcCClassss = sum1(10, 2)
print(&swift调用没有头文件的C语言类输出:\(funcCClassss)&)//12
//swift调用c函数(有头文件)
let funcCClass33 = sum3(10, 3)
print(&swift调用含有头文件的C语言类输出:\(funcCClass33)&)
到这里,就已经汇编成功了,下面是运行的结果
swift调用OC方法输出result:50
15:31:00.791 SwiftTest[] swift调用OC方法输出result:50
15:31:00.807 SwiftTest[] OC调用swift函数输出 Hellojeck!
swift调用OC类中的C函数输出:11
swift调用C函数输出result:30
swift调用没有头文件的C语言类输出:12
swift调用有头文件的C函数输出:20
swift调用含有头文件的C语言类输出:13
最后,还得要强调一下:
1.Swift调用OC的方法,关键是桥接头文件,这个必须创建正确并且配置正确,然后把你想要调用的OC或者C的头文件(没有头文件也要声明函数)导入到桥接头文件里,Swift才能正常调用OC和C;
2.在OC中要想使用某个类,必须有头文件,而swift文件却没有头文件,所在咱们想必也需要产生一个头文件,但对于OC调用swift 的头文件比较特殊.因头文件里面的机制是自动生成的,不建议手写.(注意:系统设置的头文件,在工程中是看不到的.)
3.其实,可以选中targets-&build settings -&packaging-&Product Module Name, 在这里查看和设置模块名,这个名称很重要 swift 的头文件就是根据这个来命名的。(我的图片为啥上传不了了,我借几张图说明一下吧)
虽然你看图中有这个import &SwiftModule-swift.h&但你在整个工程中是找不到这个文件的,但可以使用CMD+ 鼠标点击可看这个头文件中的内容。
虽然你看图中有这个import &SwiftModule-swift.h&但你在整个工程中是找不到这个文件的,但可以使用CMD+ 鼠标点击可看这个头文件中的内容。
凡是用Swift写的类,如果不继成自NSObject或NSObject 的派生类,哪么编译后将不会生成对应的转换类。从而使得OC 中找不到相应的声明。
如我的例子中 class Act 这样不会被编译到SwiftModule-swift.h中,但写为 class Act : NSObject,就可以编译出相应的声明。另外可以使用@objc加以声明,但这个还是一样,类最好继承NSObject下来。就像下面:
import Foundation
@objc(Act)
func hasAct(tag:Int) -& String
switch (tag)
case 1:return &Movie&
case 2:return &CCTV&
case 3:return &Sport TV&
default:return &Area TV&
@objc(init)//原本以为加上这个alloc就可以找到,但不行的。。。
println(&act constructor is called.&)
println(&act destroyed is called.&)
但是在使用时你就会发现
act = [[Act alloc]init]; //报错,找不到alloc,因此建议大家还是继承NSObject.
虽然你看图中有这个import &SwiftModule-swift.h&但你在整个工程中是找不到这个文件的,但可以使用CMD+ 鼠标点击可看这个头文件中的内容。iOS开发之Swift基本语法详解 - CSDN博客
iOS开发之Swift基本语法详解
Swift语言简介
2010 年 7 月,苹果开发者工具部门总监 Chris Lattner(克里斯·拉特纳)开始着手Swift 编程语言的设计工作,用时一年时间,完成开发语言基本架构,经历了4年的开发周期,终于在2014 年 6 月Apple WWDC 发表,用来撰写 OS X 和 iOS 应用程序等。
Swift较Objective-C优点 ?
快速、现代、安全、互动,而且明显优于 Objective-C语言;取消了 Objective-C 的指针及其他不安全访问的使用;舍弃 Objective C 早期应用Smalltalk的语法,全面改为
句点表示法;提供了类似 Java 的命名空间(namespace)、泛型(generic)、运算对象重载(operator overloading)等新概念。
基本知识点详解
常量与变量
let声明常量,var声明变量,打印print()枚举类型:枚举名称点枚举值(点语法表示)常量、变量可用任何字符表示,常量必须在定义时初始化, 否则会报错每行语句后不需添加分号(添加也正确),若是多条语句则需添加分号区别若在定义的同时并初始化 - 没有必要指定数据类型,若定义时没初始化 - 必须指定数据类型常量、变量名不能包含数学符号、箭头、保留的/非法的Unicode 码位、连线与制表符、也不能以数字开头,但可在常量、变量名其他地方包含数字Swift对数据类型要求非常严格,若要转换,则必须显示转换;
小数默认是Double类型整数默认是Int类型
var 2x = 50
本文已收录于以下专栏:
相关文章推荐
原文地址:http://www./lib/view/open4.html
1.什么是Swift
Swift是苹果于2014年W...
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
要不是swift的出现我永远都不会学习IOS开发,不过swift的一些基本用法还是需要动手写一写的。//: Playground - noun: a place where people can pl...
运算符是检查、改变、合并值的特殊符号或短语。例如,加号+ 将两个数相加(如let i = 1 + 2 )。复杂些的运算例如逻辑与运算符&& (如if enteredDoorCode && passed...
1、浮点数float和double的区分
一、OC简介
Objective-C语法之Objective-C语言和IOS系统(简介,语法,系统结构)
Objective-C,是扩充C的面向对象编程语言。它主要使用于Mac OS Ob...
【主要内容】
2.Hello World
3.常量和变量
4.类型标注
5.常量和变量的命名
6. 输出常量和变量
8.分号 
1.1 整数...
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)关于 iOS 10 的更多内容:
评论(${commentLength})
请勾选举报理由
${ item.text }
0" v-cloak>
${ related.released_at * 1000 | friendlyTime }
${related.summary}
${ related.likes_count }Swift闭包详解_C语言中文网
&&/&&&&/&&&&/&&
闭包是功能性自包含模块,可以在代码中被传递和使用。&Swift&中的闭包与&C&和&Objective-C中的&blocks&以及其他一些编程语言中的&lambdas&比较相似。
闭包可以&捕获&和存储其所在上下文中任意常量和变量的引用。 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift会为您管理在&捕获&过程中涉及到的内存操作。
注意:如果您不熟悉&捕获&(capturing) 这个概念也不用担心,后面会详细对其进行介绍。
在章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一:
全局函数是一个有名字但不会捕获任何值的闭包
嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包
闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的没有名字的闭包
Swift的闭包表达式拥有简洁的风格,并鼓励在常见场景中以实现语法优化,主要优化如下:
利用上下文推断参数和返回值类型
单表达式(single-expression)闭包可以省略&return&关键字
参数名称简写
Trailing 闭包语法
闭包表达式
嵌套函数是一种在较复杂函数中方便进行命名和定义自包含代码模块的方式。 当然,有时候撰写小巧的没有完整定义和命名的类函数结构也是很有用处的,尤其是在处理一些函数并需要将另外一些函数作为该函数的参数时。
闭包表达式是一种利用简洁语法构建内联闭包的方式。 闭包表达式提供了一些语法优化,使得撰写闭包变得简单明了。 下面闭包表达式的例子通过使用几次迭代展示了&sort&函数定义和语法优化的方式。 每一次迭代都用更简洁的方式描述了相同的功能。
Swift 标准库提供了&sort&函数,会根据您提供的排序闭包将已知类型数组中的值进行排序。 一旦排序完成,函数会返回一个与原数组大小相同的新数组,该数组中包含已经正确排序的同类型元素。
下面的闭包表达式示例使用&sort&函数对一个&String&类型的数组进行字母逆序排序,以下是初始数组值:
let names = [&Chris&, &Alex&, &Ewa&, &Barry&, &Daniella&]
排序函数有两个参数:
已知类型值的数组。
一个闭包,采用相同类型的数组的内容的两个参数,并返回一个布尔值来表示是否将第一个值在排序时放到第二个值的前面或是后面。如果第一个值应该出现第二个值之前,闭包需要返回true,否则返回false。
该例子对一个&String&类型的数组进行排序,因此排序闭包需为&(String, String) -& Bool&类型的函数。
提供排序闭包的一种方式是撰写一个符合其类型要求的普通函数,并将其作为&sort&函数的第二个参数传入:
func backwards(s1: String, s2: String) -& Bool {
return s1 & s2
var reversed = sort(names, backwards)
// reversed is equal to [&Ewa&, &Daniella&, &Chris&, &Barry&, &Alex&]
如果第一个字符串 (s1) 大于第二个字符串 (s2),backwards&函数则返回&true,表示在新的数组中&s1&应该出现在&s2&前。 字符中的 &大于& 表示 &按照字母顺序后出现&。 这意味着字母 &B& 大于字母 &A&, 字符串 &Tom& 大于字符串 &Tim&。 其将进行字母逆序排序,&Barry& 将会排在 &Alex& 之后,一次类推。
然而,这是一个相当冗长的方式,本质上只是写了一个单表达式函数 (a & b)。 在下面的例子中,利用闭合表达式语法可以更好的构造一个内联排序闭包。
闭包表达式语法
闭包表达式语法有如下一般形式:
{ (parameters) -& returnType in
statements
闭包表达式语法可以使用常量、变量和&inout&类型作为参数,但不提供默认值。 也可以在参数列表的最后使用可变参数。元组也可以作为参数和返回值。
下面的例子展示了之前&backwards&函数对应的闭包表达式版本的代码:
reversed = sort(names, { (s1: String, s2: String) -& Bool in
return s1 & s2
需要注意的是内联闭包参数和返回值类型声明与&backwards&函数类型声明相同。 在这两种方式中,都写成了 (s1: String, s2: String) -& Bool类型。 然而在内联闭包表达式中,函数和返回值类型都写在大括号内,而不是大括号外。
闭包的函数体部分由关键字&in&引入。 该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始。
因为这个闭包的函数体部分如此短以至于可以将其改写成一行代码:
reversed = sort(names, { (s1: String, s2: String) -& Bool in return s1 & s2 } )
这说明&sort&函数的整体调用保持不变,一对圆括号仍然包裹住了函数中整个参数集合。而其中一个参数现在变成了内联闭包 (相比于&backwards&版本的代码)。
根据上下文推断类型
因为排序闭包是作为函数的参数进行传入的,Swift可以推断其参数和返回值的类型。&sort&期望第二个参数是类型为&(String, String) -& Bool&的函数,因此实际上&String,&String&和&Bool&类型并不需要作为闭包表达式定义中的一部分。 因为所有的类型都可以被正确推断,返回箭头 (-&) 和 围绕在参数周围的括号也可以被省略:
reversed = sort(names, { s1, s2 in return s1 & s2 } )
实际上任何情况下,通过内联闭包表达式构造的闭包作为参数传递给函数时,都可以推断出闭包的参数和返回值类型,这意味着您几乎不需要利用完整格式构造任何内联闭包。
然而,你也可以使用明确的类型,如果你想它避免读者阅读可能存在的歧义,这样还是值得鼓励的。这个排序函数例子,闭包的目的是很明确的,即排序被替换,而且对读者来说可以安全的假设闭包可能会使用字符串值,因为它正协助一个字符串数组进行排序。
单行表达式闭包可以省略&return
单行表达式闭包可以通过隐藏&return&关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为:
reversed = sort(names, { s1, s2 in s1 & s2 } )
在这个例子中,sort&函数的第二个参数函数类型明确了闭包必须返回一个&Bool&类型值。 因为闭包函数体只包含了一个单一表达式 (s1 & s2),该表达式返回&Bool&类型值,因此这里没有歧义,return关键字可以省略。
参数名简写
Swift&自动为内联函数提供了参数名称简写功能,您可以直接通过&$0,$1,$2等名字来引用的闭包的参数的值。
如果您在闭包表达式中使用参数名称简写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称简写的类型会通过函数类型进行推断。&in&关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
reversed = sort(names, { $0 & $1 } )
在这个例子中,$0&和&$1&表示闭包中第一个和第二个&String&类型的参数。
运算符函数
实际上还有一种更简短的方式来撰写上面例子中的闭包表达式。&Swift的&String&类型定义了关于大于号 (&) 的字符串实现,让其作为一个函数接受两个&String&类型的参数并返回&Bool&类型的值。 而这正好与&sort&函数的第二个参数需要的函数类型相符合。 因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现:
reversed = sort(names, &)
更多关于运算符表达式的内容请查看&&。
Trailing 闭包
如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用 trailing 闭包来增强函数的可读性。
Trailing 闭包是一个书写在函数括号之外(之后)的闭包表达式,函数支持将其作为最后一个参数调用。
func someFunctionThatTakesAClosure(closure: () -& ()) {
// 函数体部分
// 以下是不使用 trailing 闭包进行函数调用
someFunctionThatTakesAClosure({
// 闭包主体部分
// 以下是使用 trailing 闭包进行函数调用
someFunctionThatTakesAClosure() {
// 闭包主体部分
注意:如果函数只需要闭包表达式一个参数,当您使用 trailing 闭包时,您甚至可以把 () 省略掉。 NOTE
在上例中作为&sort&函数参数的字符串排序闭包可以改写为:
reversed = sort(names) { $0 & $1 }
当闭包非常长以至于不能在一行中进行书写时,Trailing 闭包就变得非常有用。 举例来说,Swift&的&Array&类型有一个&map&方法,其获取一个闭包表达式作为其唯一参数。 数组中的每一个元素调用一次该闭包函数,并返回该元素所映射的值(也可以是不同类型的值)。 具体的映射方式和返回值类型由闭包来指定。
当提供给数组闭包函数后,map&方法将返回一个新的数组,数组中包含了与原数组一一对应的映射后的值。
下例介绍了如何在&map&方法中使用 trailing 闭包将&Int&类型数组&[16,58,510]&转换为包含对应&String&类型的数组&[&OneSix&, &FiveEight&, &FiveOneZero&]:
let digitNames = [
0: &Zero&, 1: &One&, 2: &Two&, 3: &Three&, 4: &Four&,
5: &Five&, 6: &Six&, 7: &Seven&, 8: &Eight&, 9: &Nine&
let numbers = [16, 58, 510]
上面的代码创建了整数数字到他们的英文名字之间映射字典。 同时定义了一个准备转换为字符串的整型数组。
您现在可以通过传递一个 trailing 闭包给&numbers&的&map&方法来创建对应的字符串版本数组。 需要注意的时调用&numbers.map不需要在&map&后面包含任何括号,因为只需要传递闭包表达式这一个参数,并且该闭包表达式参数通过 trailing 方式进行撰写:
let strings = numbers.map {
(var number) -& String in
var output = &&
while number & 0 {
output = digitNames[number % 10]! + output
number /= 10
return output
// strings 常量被推断为字符串类型数组,即 String[]
// 其值为 [&OneSix&, &FiveEight&, &FiveOneZero&]
map&在数组中为每一个元素调用了闭包表达式。 您不需要指定闭包的输入参数&number&的类型,因为可以通过要映射的数组类型进行推断。
闭包&number&参数被声明为一个变量参数 (变量的具体描述请参看),因此可以在闭包函数体内对其进行修改。 闭包表达式制定了返回值类型为&String,以表明存储映射值的新数组类型为&String。
闭包表达式在每次被调用的时候创建了一个字符串并返回。 其使用求余运算符&(number % 10)&计算最后一位数字并利用digitNames&字典获取所映射的字符串。
注意:字典&digitNames&下标后跟着一个叹号 (!),因为字典下标返回一个可选值 (optional value),表明即使该&key不存在也不会查找失败。 在上例中,它保证了&number % 10&可以总是作为一个&digitNames&字典的有效下标&key。 因此叹号可以用于强展开&(force-unwrap)&存储在可选下标项中的&String&类型值。
从&digitNames&字典中获取的字符串被添加到输出的前部,逆序建立了一个字符串版本的数字。 (在表达式&number % 10中,如果number为16,则返回6,58返回8,510返回0)。
number&变量之后除以10。 因为其是整数,在计算过程中未除尽部分被忽略。 因此 16变成了1,58变成了5,510变成了51。
整个过程重复进行,直到&number /= 10&为0,这时闭包会将字符串输出,而map函数则会将字符串添加到所映射的数组中。
上例中 trailing 闭包语法在函数后整洁封装了具体的闭包功能,而不再需要将整个闭包包裹在&map&函数的括号内。
捕获 (Caputure)
闭包可以在其定义的上下文中捕获常量或变量。 即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数体内的函数。 嵌套函数可以捕获其外部函数所有的参数以及定义的常量和变量。
下例为一个叫做&makeIncrementor&的函数,其包含了一个叫做&incrementor&嵌套函数。 嵌套函数&incrementor&从上下文中捕获了两个值,runningTotal&和&amount。 之后&makeIncrementor&将&incrementor&作为闭包返回。 每次调用&incrementor&时,其会以&amount&作为增量增加&runningTotal&的值。
func makeIncrementor(forIncrement amount: Int) -& () -& Int {
var runningTotal = 0
func incrementor() -& Int {
runningTotal += amount
return runningTotal
return incrementor
makeIncrementor&返回类型为&() -& Int。 这意味着其返回的是一个函数,而不是一个简单类型值。 该函数在每次调用时不接受参数只返回一个&Int&类型的值。 关于函数返回其他函数的内容,请查看。
makeIncrementor&函数定义了一个整型变量&runningTotal&(初始为0) 用来存储当前增加总数。 该值通过&incrementor&返回。
makeIncrementor&有一个&Int&类型的参数,其外部命名为&forIncrement, 内部命名为&amount,表示每次&incrementor&被调用时runningTotal&将要增加的量。
incrementor&函数用来执行实际的增加操作。 该函数简单地使&runningTotal&增加&amount,并将其返回。
如果我们单独看这个函数,会发现看上去不同寻常:
func incrementor() -& Int {
runningTotal += amount
return runningTotal
incrementor&函数并没有获取任何参数,但是在函数体内访问了&runningTotal&和&amount&变量。这是因为其通过捕获在包含它的函数体内已经存在的&runningTotal&和&amount&变量而实现。
由于没有修改&amount&变量,incrementor&实际上捕获并存储了该变量的一个副本,而该副本随着&incrementor&一同被存储。
然而,因为每次调用该函数的时候都会修改&runningTotal&的值,incrementor&捕获了当前&runningTotal&变量的引用,而不是仅仅复制该变量的初始值。捕获一个引用保证了当&makeIncrementor&结束时候并不会消失,也保证了当下一次执行&incrementor&函数时,runningTotal&可以继续增加。
注意:Swift&会决定捕获引用还是拷贝值。 您不需要标注&amount&或者&runningTotal&来声明在嵌入的&incrementor&函数中的使用方式。&Swift&同时也处理&runingTotal&变量的内存管理操作,如果不再被&incrementor&函数使用,则会被清除。
下面为一个使用&makeIncrementor&的例子:
let incrementByTen = makeIncrementor(forIncrement: 10)
该例子定义了一个叫做&incrementByTen&的常量,该常量指向一个每次调用会加10的&incrementor&函数。 调用这个函数多次可以得到以下结果:
incrementByTen()
// 返回的值为10
incrementByTen()
// 返回的值为20
incrementByTen()
// 返回的值为30
如果您创建了另一个&incrementor,其会有一个属于自己的独立的&runningTotal&变量的引用。 下面的例子中,incrementBySevne&捕获了一个新的&runningTotal&变量,该变量和&incrementByTen&中捕获的变量没有任何联系:
let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven()
// 返回的值为7
incrementByTen()
// 返回的值为40
注意:如果您闭包分配给一个类实例的属性,并且该闭包通过指向该实例或其成员来捕获了该实例,您将创建一个在闭包和实例间的强引用环。&Swift&使用捕获列表来打破这种强引用环。更多信息,请参考&。
闭包是引用类型
上面的例子中,incrementBySeven&和&incrementByTen&是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量值。 这是因为函数和闭包都是引用类型。
无论您将函数/闭包赋值给一个常量还是变量,您实际上都是将常量/变量的值设置为对应函数/闭包的引用。 上面的例子中,incrementByTen&指向闭包的引用是一个常量,而并非闭包内容本身。
这也意味着如果您将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包:
let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// 返回的值为50
编程帮,一个分享编程知识的公众号。跟着一起学习,每天都有进步。
通俗易懂,深入浅出,一篇文章只讲一个知识点。
文章不深奥,不需要钻研,在公交、在地铁、在厕所都可以阅读,随时随地涨姿势。
文章不涉及代码,不烧脑细胞,人人都可以学习。
当你决定关注「编程帮」,你已然超越了90%的程序员!
微信扫描二维码关注
Swift基础教程
Swift语言参考
与Cocoa和Objective-C混合编程

我要回帖

更多关于 正则表达式语法 的文章

 

随机推荐