函数
func x(a:Int, b:Int) {} func x(a:Int, b:Int) -> Void {} func x(a:Int, b:Int) ->(Int,Int) {}
外部参数名
func x(width a:Int,height b:Int) -> Int {} func x(#a:Int,#b:Int) -> Int {}
//一般情况下可以不指定外部参数名,直接调用函数,但使用外部参数名,可以显著提高代码可读性:
func helloWithName(name: String, age: Int, location: String) {
println("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")
} helloWithName("Mr. Roboto", 5, "San Francisco") //但是在类 (或者结构、枚举) 中的时候,会自动分配外部参数名 (第一个除外)
class MyFunClass {
func helloWithName(name: String, age: Int, location: String) {
println("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")
}
// 可强制给第一个参数也加上外部参数名
func helloWithName2(#name: String, age: Int, location: String) {
println("Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")
}
}
let myFunClass = MyFunClass()
myFunClass.helloWithName("Mr. Roboto", age: 5, location: "San Francisco")
myFunClass.helloWithName2(name: "Mr. Roboto", age: 5, location: "San Francisco") //不想要外部变量名,那么可以用 _ 来代替:
struct Celsius {
var temperatureInCelsius: Double
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
init(_ celsius: Double) {
temperatureInCelsius = celsius
}
} let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius 是 100.0 let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius 是 0.0 let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius 是 37.0
//对外部参数名的娴熟应用可以极好的抽象初始化过程。
参数默认值
/// 有缺省值的参数一般放在参数列表末尾
func makeCoffee(type: String = "卡布奇诺")-> String{
return "制作一杯\(type)咖啡。"
}
let coffee1 = makeCoffee() //制作一杯卡布奇诺咖啡。
//外部参数名不可省
let coffee2 = makeCoffee(type :"拿铁") //制作一杯拿铁咖啡。 //可以用“_”申明不需要外部参数名
func drive(_ somebody:String = "我", _ car:String = "车"){
println("\(somebody)开着\(car)离开了")
}
drive() //我开着车离开了
drive("小李","一辆老爷车")
可变参数
// 如果有多个参数,可变参数必须放在参数列表末尾,所以也只能有一个可变参数
func sum(numbers: Double...)-> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total
} func sum(numbers:[Double])-> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total
} println("\(sum(100.0,20,30))")
println("\(sum([100.0,20,30]))")
println("\(sum(80,30))")
println("\(sum([80,30]))") //如果可变参数和缺省参数同时存在,缺省参数失效
func sumAddValue(_ addValue:String = "S", numbers: Int...) -> String {
var sum = ""
for number in numbers {
sum += number.description + addValue
}
return sum
}
sumAddValue(2, 2,4,5) //报错
常量与变量参数
// 形参默认声明为常量,无法在函数体中改变参数值。可以显示地声明为变量
/// 右对齐函数:
func alignRight(var string: String, num: Int, pad: Character) -> String {
let amountToPad = num - count(string)
if amountToPad < 1 {
return string
}
let padString = String(pad)
for _ in 1...amountToPad {
string = padString + string
}
return string
}
let originalString = "hello"
let paddedString = alignRight(originalString, 8, "-") // "---hello"
输入输出参数:值类型的引用传递 用inout 实现 调用是 参数前加&, 另参看运算符重载
func increment(inout value: Double, amount: Double = 1.0) {
value + =amount
} var value : Double =10.0
increment(&value)
println(value)
increment(&value,amount: 100.0)
println(value)
返回值
无返回值 func 函数名(参数列表){} 或 func 函数名 (参数列表) -> (){}/*()为空的元组*/ 或 func 函数名 ->Void (函数列表){}
多个返回值 可采用引用传递 或返回 元组
func position(t: Double,speed: (x: Int, y: Int)) -> (x:Int, y:Int) {
var posx:Int = speed.x * Int (t)
var posy:Int = speed.y * Int (t)
return (posx, posy)
} let move = position(60.0, (10,-5))
println("1小时后物体的位置坐标为(\(move.x),\(move.y))")
func componentsFromUrlString(urlString: String) -> (host: String?, path: String?) { let url = NSURL(string: urlString) return (url?.host, url?.path) } let urlComponents
= componentsFromUrlString("http://why/233;param?foo=1&baa=2#fragment") switch (urlComponents.host, urlComponents.path) { case let (.Some(host), .Some(path)): println("host \(host) and path \(path)") case let (.Some(host), .None): println("only host \(host)") case let (.None, .Some(path)): println("only path \(path)") case let (.None, .None): println("This is not a url!") }
泛型函数
func isEquals<T: Comparable> (a: T, b: T) ->bool { return (a == b) }
func isEquals<T> (a: T, b: T) -> T {...}
func isEquals<T, U> (a: T, b: U) -> T {... }
闭包
函数式编程
*中函数式编程的定义: 函数式编程是一种编程模型,他将计算机运算看做是数学中函数的计算,并且避免了状态以及变量的概念。
无论多少进程在跑,因为保证了没有赋值操作,也就不会影响最终的运行结果,但也无法保存状态。
在其他编程模式中,用变量保存状态,因而并发编程,需要考虑”死锁“,需要担心一个线程的数据被另一个线程修改。而函数式编程本身是为了简化多核并行程序的设计。不依赖变量保存状态也就可以很放心地把工作分摊给多个线程,部署并发编程。
函数作为first class 是函数式编程的基础。努力用函数来表达所有的概念,完成所有的操作。
在面向对象编程中,我们把对象传来传去,那在函数式编程中,我们要做的是把函数传来传去。用函数来抽象,就是要用到高阶函数。
在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:
- 接受一个或多个函数作为输入
- 输出一个函数
f(x) = y ,无论在任何情况下相同的x传入只能返回相同的y,这就要求除了传入的x外,函数执行过程中的其他相关数据都不能发生变化。这样在实际操作中,意味着函数需要保持独立,需要保存环境。这些都需要用函数参数来保存,作为附属品一起传递。这是递归的模式。因而减少可变参数数量就变得非常重要,需要把树状递归转化为尾递归(currying),从而使对栈空间的占用处于常数级。
swift 中:
可以定义一个函数类型的常量或变量,并且可以赋值。
函数类型可以作为参数类型,也可以作为返回值类型。
函数是first class ,和其他基本数据类型一样,处于平等地位
//变量
//我们可以定义一个变量,这个变量的类型是函数类型:
func addTwoInts(a: Int, b: Int) -> Int {
return a + b
}
let anotherMathFunction = addTwoInts
anotherMathFunction(1,2) // 3 //参数 //函数既然是类型的一种,那么显然也是可以作为参数传递的: func addTwoInts2(a: Int, b: Int) -> Int {
return a + b
} func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
println("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts2, 3, 5) // 将参数2和参数3作为参数传给参数1的函数 //返回值
func stepForward(input: Int) -> Int {
return input + 1
} func stepBackward(input: Int) -> Int {
return input - 1
} func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
return backwards ? stepBackward : stepForward
} var currentValue = 3
let moveNearerToZero = chooseStepFunction(currentValue > 0) println("Counting to zero:")
while currentValue != 0 {
println("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
println("zero!") // 3...
// 2...
// 1...
// zero! //别名 typealias typealias lotteryOutputHandler = (String, Int) -> String func luckyNumberForName(name: String, #lotteryHandler: lotteryOutputHandler) -> String {
let luckyNumber = Int(arc4random() % 100)
return lotteryHandler(name, luckyNumber)
} luckyNumberForName("Mr. Roboto"){
name, number in
return "\(name)'s' lucky number is \(number)"
}
// Mr. Roboto's lucky number is 33 // 嵌套
func chooseStepFunction2(backwards: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backwards ? stepBackward : stepForward
}
var currentValue2 = -4
let moveNearerToZero2 = chooseStepFunction2(currentValue < 0) while currentValue2 != 0 {
println("\(currentValue2)... ")
currentValue2 = moveNearerToZero2(currentValue2)
} // 类似计算属性一样的嵌套函数写法
func getLogicValue(value:Int)->Bool{
// 类似计算属性一样的写法
var boolVale:Bool{
switch value{
case 0:
return false
default:
return true
}
}
println(boolVale) // 每次调用都会执行
return boolVale
} getLogicValue(11)
getLogicValue(0)
闭包是一个代码块,它可以捕获其上下文中任意的变量和常量,延长其的生存周期以供自己使用,把函数以及这些变量包起来,而可以独立完成一个完整的功能。同时它如同普通数据类型的数据一样可以做参数,可以做返回值,参与了其他代码模块的构建。
var result: (Int, Int)-> Int
//闭包表达式,为自包含的匿名函数代码模块
// {(参数列表) ->返回值类型 in 语句组}
result = {(a:Int,b:Int)-> Int in return a-b} //由于swift的类型推断,上列式子可以简化
result = {a, b in return a - b} //省去参数和返回值类型
result = {a, b in a - b} //如果语句组只有一条语句 关键字 return 可省略
result = {$0 - $1} //使用参数名称缩写功能 省去 参数列表 //无参数的闭包
var result2 : () ->()
result2 = {println("hello")} //闭包作为参数时可能影响可读性,于是有了尾随闭包(闭包必须是最后一个参数)
//如果除了闭包没有其他参数了,甚至可以把小括号也去掉。 func repeat (count: Int, task: ()->()) {
for i in 0...count {
task ()
}
}
repeat(2, {
println("hello")
}
)
//改写为
repeat(2) {
println("hello")
} //闭包作为返回值
func caculate(#op:String)->(Int,Int)->Int
{
var result:(Int,Int)->Int;
switch(op){
case "+":result={(a:Int,b:Int)->Int in return a+b}
default:result={$0 > $1 ?$0-$1:$1-$0}
}
return result;
}
let f1 = caculate(op: "-")
println(f1(1,2))
println(f1(5,2)) let c1={$0 > $1 ?$0-$1:$1-$0}(6,2)
println(c1) let f4 :(Int,Int)->Int = {$0 > $1 ?$0-$1:$1-$0}
let yyyy = f4(2,2)
一个测试
typealias block = ()->()
class X{
func get(n:Int)->[block]{
var list = [block]()
for var i = 0; i < n; i++ {
list.append(
{
[weak self] in
println(self)
println(i)
}
)
}
return list
}
} class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: Common.SIZE) var x:X? = X();
let list2 = x!.get(13) let queue = dispatch_queue_create("cn.itcast.queue", nil)
for ii in list2{
dispatch_async(queue, ii)
} println("ss:\(x)")
return true
}
// ....
} 输出:
/*
Ospst:iOopntailo(nba2lb(mba2lblm.aXl)l
.X)1
3
nil
13
nil
13
nil
13
nil
13
nil
13
nil
13
nil
13
nil
13
nil
13
nil
13
nil
13
nil
13
*/
/*
异步输出里的第一轮时x还在,与主线程的输出 重叠了。
在主线程执行完后 实例x即已释放,异步线程的后面几轮循环时,x实例已不存在,
但x 内的局部变量 i 依然可操作,
*/
修改版
typealias block = ()->()
class X{
func get(n:Int)->[block]{
var list = [block]()
var i = 0
for ; i < n; i++ {
list.append(
{
[weak self] in
println(self)
i++
println(i)
}
)
}
println(++i)
return list
}
} class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: Common.SIZE) var x:X? = X();
let list2 = x!.get(13) let queue = dispatch_queue_create("cn.itcast.queue", nil)
for ii in list2{
dispatch_async(queue, ii)
} println("ss:\(x)")
return true
}
// ....
} 输出:
/*
14
Optionals(s:Optibonal(b22bmall.bX)
mall.X)
15
nil
16
nil
17
nil
18
nil
19
nil
20
nil
21
nil
22
nil
23
nil
24
nil
25
nil
26
nil
27
*/
闭包捕获的参数列表中, 实例的属性和方法的调用都会捕获实例变量,而局部变量的使用则仅捕获其自身。
但在测试2里, 外部方法内对局部变量 i 的修改 可以影响到闭包内的 i,同时闭包内对 i 的修改也会影响到其他闭包内 i 的值。这样实现了内外的一致性。
猜测是类似递归函数那样的参数捕获。即被捕获的变量加入了闭包函数的参数列表,那么对于值类型,为了保证一致性,传递的该是指针(inout)。
ARC
自动引用计数,swift中的内存管理方式,应用于引用类型(类,函数,闭包)
跟踪内存中的实例,每多一个变量或常量指向它时,它的引用计数加一,每少一个,引用计数减一,当计数为0时自动释放该实例所占内存空间。
强引用(strong reference type)
强引用(strong reference type) 会产生计数加一的效果
如果有多个实例的属性在互相引用,且都是强引用时,一旦形成闭环,则除非程序员主动介入解环,即便指向这些实例的变量,常量都已生命周期结束,这几个实例所占的内存也不会自动释放。
解决办法:
弱引用(weak reference), 无主引用(Unowned reference) 及 捕获列表(capture list)
弱引用与无主引用的区别
弱引用声明为可选类型,无主引用声明为非可选类型,但二者都不会产生引用计数。因而被它们指向的实例是可能在中途自动释放的。
区别在于: 弱引用指向的实例在被释放时会主动更新所有指向它的弱引用为nil(所以弱引用在性能上自然比无主引用要差一些), 这样弱引用被调用时,就可以先判别是非为nil,以避免程序奔溃。
而无主引用则不能判别是否为nil,当被指向的实例已经不存在时,就会导致程序奔溃。
所以要使用无主引用,即假如实例A的属性指向实例B,则要求B实例在整个A实例存活期间,始终存在,即B一定要死在A的后面。
所以一般情况下,会选择使用弱引用
捕获列表是弱引用与无助引用在闭包中的运用。
class WeatherReport:NSObject{
lazy var reports:()->String = {
[weak self] in
if let strongSelf = self{
return strongSelf.description
}
else{
return ""
}
}
} // 写在playground 时 a= nil 并没有把a所占空间释放掉
// 在app 中执行正常
var a:UIView? = UIView()
println(a!.description)
//<UIView: 0x7fbfeae0daa0; frame = (0 0; 0 0); layer = <CALayer: 0x7fbfeae0dbb0>> var b = UIView()
let closure:(Int)->() = {
[weak a,unowned b] (num:Int) in
if let stronga = a{
println( stronga.description + b.description)
}
else{
println( num.description)
}
} closure(1)
//<UIView: 0x7fbfeae0daa0; frame = (0 0; 0 0);
//layer = <CALayer: 0x7fbfeae0dbb0>><UIView: 0x7fbfeac5fd60;
//frame = (0 0; 0 0); layer = <CALayer: 0x7fbfeac5fe70>>
a = nil
closure(3)
//3
柯里化 (currying)
//柯里化背后的基本想法是,函数可以局部应用,意思是一些参数值可以在函数调用之前被指定或者绑定。这个部分函数的调用会返回一个新的函数。
//显示柯里化
func curryUnnamed2(first a:Int)->((Int)->Int){
func curryInner(b:Int)->Int{
return a + b
}
return curryInner
} // 隐式柯里化
func curryUnnamed(first a:Int)(second b:Int)->Int{
return a + b
}
let result = curryUnnamed(first: 1)(second: 2) // 3 let f1 = curryUnnamed(first: 1) //(second b:Int)->Int
let result2 = f1(second: 2)
/// 普通形式
func salary(name:String,base:Int,to:Int)->Bool{
println("\(name)收到工资:\(base) 加班费:\(to)")
return true
} /// 柯里化形式
func salary(name:String)(base:Int)(to:Int)->Bool{
println("\(name)收到工资:\(base) 加班费:\(to)")
return true
} typealias paySalaryTypeCurried = Int->Int->Bool
func success(type:String,salary:Int->Int->Bool){
if type == "砖工"{
salary(200)(250)
}
else{
salary(100)(100)
}
}
func fail(reason:String){
println("跳了")
} func begSalaryByFormean(who:String,success:(String, paySalaryTypeCurried)->(),fail:(String)->()){
if who == "良心企业"{
success("砖工", salary("老张"))
success("瓦工", salary("老李"))
}
else{
fail("")
}
}
begSalaryByFormean("良心企业", success, fail)
class MyHelloWorldClass { func helloWithName(name: String) -> String {
return "hello, \(name)"
}
} let helloWithNameFunc = MyHelloWorldClass.helloWithName
//let helloWithNameFunc:MyHelloWorldClass->String->String = MyHelloWorldClass.helloWithName
let myHelloWorldClassInstance = MyHelloWorldClass()
helloWithNameFunc(myHelloWorldClassInstance)("Mr. Roboto")
swift中的反射(2.0后有较大改变,待修改)
http://www.cocoachina.com/industry/20140623/8923.html
protocol Reflectable {
func getMirror() -> Mirror
}
protocol Mirror {
var value: Any { get }
var valueType: Any.Type { get }
var objectIdentifier: ObjectIdentifier? { get }
var count: Int { get }
subscript (i: Int) -> (String, Mirror) { get }
var summary: String { get }
var quickLookObject: QuickLookObject? { get }
var disposition: MirrorDisposition { get }
}
// metatype-type –> type.Type
// type-as-value –> type.self
// 其中 metatype-type 出现在代码中需要类型的地方, type-as-value 出现在代码中需要值、变量的地方。
var a :Int.Type
var b:UIImage.Type
var c:UITableViewDelegate.Type UITableView().registerClass(UITableViewCell.self, forCellReuseIdentifier: "reuseCell") //反射信息用 Mirror 类型表示,类型协议是 Reflectable
protocol Reflectable {
func getMirror() -> Mirror
}
protocol Mirror {
var value: Any { get }
var valueType: Any.Type { get }
var objectIdentifier: ObjectIdentifier? { get }
var count: Int { get }
subscript (i: Int) -> (String, Mirror) { get }
var summary: String { get }
var quickLookObject: QuickLookObject? { get }
var disposition: MirrorDisposition { get }
}
1.value 相当于变量的 as Any 操作
2.valueType 获得变量类型
3.objectIdentifier 相当于一个 UInt 作用未知,可能是 metadata 表用到
4.count 子项目个数(可以是类、结构体的成员变量,也可以是字典,数组的数据)
5.subscript(Int) 访问子项目, 和子项目的名字
6.summary 相当于 description
7.quickLookObject 是一个枚举,这个在 WWDC 有讲到,就是 Playground 代码右边栏的显示内容,比如常见类型,颜色,视图都可以
8.disposition 表示变量类型的性质,基础类型 or 结构 or 类 or 枚举 or 索引对象 or … 如下
enum MirrorDisposition {
case Struct // 结构体
case Class // 类
case Enum // 枚举
case Tuple // 元组
case Aggregate // 基础类型
case IndexContainer // 索引对象
case KeyContainer // 键-值对象
case MembershipContainer // 未知
case Container // 未知
case Optional // Type?
var hashValue: Int { get }
}
- let mir = reflect(someVal)
- swift mir.valueType {
- case _ as String.Type:
- println("type = string")
- case _ as Range<Int>.Type:
- println("type = range of int")
- case _ as Dictionary<Int, Int>.Type:
- println("type = dict of int")
- case _ as Point.Type:
- println("type = a point struct")
- default:
- println("unkown type")
- }
- if mir is String.Type {
- println("!!!type => String")
- }
- for r in 0..mir.count {
- let (name, subref) = mir[r]
- prtln("name: \(name)")
- // visit sub Mirror here
- }
- .count 为字段个数。
- subscript(Int) 返回 (字段名,字段值反射 Mirror) 元组
- summary 为 mangled name
- .count 为元组子元素个数
- subscript(Int) 的 name 为 “.0”, “.1” …
- .count 为 0
- .count 为元组子元素个数
- subscript(Int) 的 name 为 “[0]”, “[1]” …
- .count 为元组子元素个数
- subscript(Int) 的 name 为 “[0]”, “[1]” … 实际访问是 (name, (reflect(key), reflect(val)))
- .count 为 0 或者 1 (对应 nil 和有值的情况)
- subscript(Int) , name 为 “Some”
let aclass: AnyClass! = NSClassFromString("UIControl")
aclass.isSubclassOfClass(UIView) //true
let superfunc = aclass.superclass //()->AnyClass?
superfunc() //UIView
aclass.superclass() //UIView let aUIControl = UIControl(frame: CGRectZero)
let super1: AnyClass? = aUIControl.superclass //UIView
let super2: AnyClass? = super1?.superclass() //UIResponder
let super3: AnyClass? = super2?.superclass() //NSObject
let super4: AnyClass? = super3?.superclass() //nil aUIControl.isKindOfClass(UIView) //true println(aclass.description()) //UIControl
println(UIView.description()) //UIView
println(UIView.self) //UIView
println(Int.self) //Swift.Int