swift学习笔记

| 分类 ios  | 标签 [swift] 

Swift有三种类型的对象: class, struct, enum

Function Parameters and Return Value

Void(函数没有返回值时返回的类型)在Swift中是真实的类型,没有返回任何值的函数实际返回的就是Void类型,也可以用()来表示。 return Void,return (),return 是一个效果。

func f() -> Void {}
func f() -> () {}
func f() {}

上面三个方法都是没有返回值的。

函数签名(Function Signature)

利用参数与返回值确定函数签名,例如(Int, Int) -> Int。对于没有参数与返回值的函数可以用Void -> Void,() -> (), Void -> (), () -> Void表示,为了一致,还是优先使用前两种。

External Parameter Names

作用:

  • 声明每个参数的目的
  • 区分函数。两个函数名字和签名可以相同,但是外部参数名不能相同
  • 帮助Swift与OC,Cocoa交互

除了第一个参数,剩下的所有的参数默认自动是外部参数。

func say(s:String, times: Int) {}

//调用
say("hi", times:3)

如果不想要外部参数,在前面加_,像下面这样:

func say(s:String, _ times: Int) {}

//调用
say("hi", 3)

一个Swift函数的名字是括号前面的名字加上外部参数的名字,如上面的say(_:times:)say(_:_:)

Overloading

两个函数如果有相同的signature但是外部参数名字不同不能说是重载;因为他们外部参数名称不同,因此他们是两个函数名不相同的函数。

Default Parameter Values

func say(s: String, times: Int = 1) {}

可以用say("hi")say("hi", times:3)来调用该函数。

Ignored Parameters

func say(s:String, times:Int, loudly _:Bool) {}
//调用
say("hi",times:3,true)

func say(s:String, times:Int, _:Int){}
//调用
say("hi", 3, true)

当参数局部名称是_时在函数体内无法读取该参数值。

Modifiable Parameter

func say(s:String, times:Int, var loudly: Bool){}

默认情况下函数参数隐式声明为常量(let),不能进行赋值。如果需要在函数体中对参数进行赋值,需要显式声明为var。虽然声明为var后可以进行赋值,但是不能修改函数体外部原来的值。如果要修改传递参数的原始的值,可以按下面操作:

  1. 把想要修改的参数声明为inout
  2. 在调用函数时,想让函数修改其值的变量必须声明为var
  3. 不要用变量来当参数,需要传递它的地址,在变量名前加&
func removeFromeString(inout s:String, character c:Character){}

var s = "hello"
removeFromString(&s, "l")

UnsafeMutablePointer

当需要与OC打交道而不是Swift时,需要使用UnsafeMutablePointer 而不是inout

func CGRectDivide(rect: CGRect, _ slice: UnsafeMutablePointer<CGRect>, _ remainder: UnsafeMutablePointer<CGRect>, _ amount: CGFloat, _ edge: CGRectEdge)

var arrow = CGRectZero
var body = CGRectZero
CGRectDivide(rect, &arrow, &body, Arrow.ARHEIGHT, .MinYEdge)

当参数是class类型时,不需要声明为inout,因为class类型是引用类型的,其他的都是值类型。

Function As Value

函数要作为值需要有类型,函数的类型就是它的signature.

func doThis(f:()->()) {
	f()
}
func whatTodo() {
	print("I did it")
}
doThis(whatTodo)

可以使用typealis给某个函数类型一个名字,如typealias VoidVoidFunc = () -> ()

Anonymous Functions

func f(finished:Bool) {
	print("finished:\(finished)")
}

{
	(finished:Bool)->() in
	print("finished:\(finished)")
}
匿名函数的使用:
UIView.animationWithDuration(0.4, animations: {
	()->() in
	self.frame.origin.y += 20
	}, completion: {
		(finished: Bool) -> () in
		print("finished:\(finished)")
})

省略返回值

UIView.animationWithDuration(0.4, animations: {
	() in
	self.frame.origin.y += 20
	}, completion: {
		(finished: Bool) in
		print("finished:\(finished)")
})

当没有参数时省略in

UIView.animationWithDuration(0.4, animations: {
	self.frame.origin.y += 20
	}, completion: {
		(finished: Bool) in
		print("finished:\(finished)")
})

省略参数类型

UIView.animationWithDuration(0.4, animations: {
	self.frame.origin.y += 20
	}, completion: {
		(finished) in
		print("finished:\(finished)")
})

省略括号

UIView.animationWithDuration(0.4, animations: {
	self.frame.origin.y += 20
	}, completion: {
		finished in
		print("finished:\(finished)")
})

即使有参数也省略in行。如果返回值可以省略,并且如果编译器知道参数类型,你可以省略in行,在匿名函数体内直接用$0,$1,..引用对应的参数。

UIView.animationWithDuration(0.4, animations: {
	self.frame.origin.y += 20
	}, completion: {
		print("finished:\($0)")
})

省略参数的名字。如果匿名函数体不需要引用参数,可以用_在in行替换参数列表,如果不需要引用任何参数,可以只用一个_来替换整个参数列表。

UIView.animationWithDuration(0.4, animations: {
	self.frame.origin.y += 20
	}, completion: {
		_ in
		print("finished:\(finished)")
})

不能同时省略in行也不通过magic name引用参数!!

省略函数参数名。如果在调用函数时匿名函数作为最后一个参数,可以在倒数第二个参数闭合函数,将没有名称的匿名函数紧跟在后面。

UIView.animationWithDuration(0.4, animations: {
	self.frame.origin.y += 20
	}){
		_ in
		print("finished:\(finished)")
}

省略调用函数的括号。如果你用了尾函数语法,并且你调用的函数只有一个函数作为参数,你可以在调用时省略空括号。

func doThis(f:()->()) {
	f()
}
doThis {
	print("hi")
}

省略关键字return

func sayHi() -> String {
	return "Hi"
}
func performAndPrint(f:()->String) {
	let s = f()
	print(s)
}
performAndPrint {
	sayHi()
}

Closure

Swift函数就是闭包。

Curried Functions(柯里化函数)

func makeRoundedRectangleMaker(sz:CGSize, _ r:CGFloat) -> () -> UIImage {
	return {
		imageOfSize(sz) {
			let p = UIBezierPath(
				rounderRect: CGRect(origin:CGPointZero, size: sz),
				cornerRadius:r)
			p.stroke()
		}
	}
}

let maker = makeRoundedRectangleMaker(CGSizeMake(45,20),8)
func makeRoundedRectangleMaker(sz:CGSize) -> (CGFloat) -> UIImage {
	return {
		r in
		imageOfSize(sz) {
			let p = UIBezierPath(
				rounderRect: CGRect(origin:CGPointZero,size: sz),
				cornerRadius:r)
			p.stroke()
		}
	}
}

let maker = makeRoundedRectangleMaker(CGSizeMake(45,20))
let image = maker(8)
func makeRoundedRectangleMaker(sz:CGSize)(_ r:CGFloat) -> UIImage {
	return imageOfSize(sz) {
			let p = UIBezierPath(
				rounderRect: CGRect(origin:CGPointZero, size: sz),
				cornerRadius:r)
			p.stroke()
	}
}

let image = makeRoundedRectangleMaker(CGSizeMake(45,20))(8)

Variable

变量的类型不能改变。

Computed Initializer

let timed : Bool = {
	if val == 1 {
		return true
	} else {
		return false
	}
}()

定义并调用匿名函数通常是唯一合法的方式来计算实例属性的初始值。因为在初始化实例属性时不能调用实例的方法(此时还没有实例,你正在创建实例)。

Computed Variables

var now: String {
	get {
		return NSDate().description
	}
	set {
		print(newValue)
	}
}

注意:

  • 变量必须声明为var,类型必须显式声明
  • get 方法必须返回与变量类型一致的值
  • setter就像是有一个参数的函数,参数的局部名称默认是newValue,也可以修改该参数的局部名称set (val) {}
  • setter函数不是必需的,如果省略setter,变量就变成只读的,如果尝试赋值会报编译错误。在swift中,一个没有setter的计算变量是创建一个只读变量的主要方式
  • 一定要有getter!!,如果没有setter, get及后面的{}可以省略。这也是只读变量的合法声明。
var now: String {
	return NSDate().description
}

Setter Observer

与声明computed Variable类似。

var s = "whatever" {
	willSet {
		print(newValue)
	}
	didSet {
		print(oldValue)
	}
}

注意:

  • 变量必须是var,可以有初始值。
  • 默认情况下willSet接收新值,局部名为newValue,同样也可以改成其他名字
  • 默认情况下didSet接收旧的值,局部名为oldValue,同样也可以改为其他名字。新值已经存储了,在didSet里可以访问到,在didSet函数里修改为其他值也是合法的。

Setter Observer函数在初始化或是在didSet里修改值时不会调用,否则会死循环!

Computed Variable不能有setter observer!

Lazy Initialization

swift中有三种类型可以initialized lazily:

  • global variables. 自动lazy.全局变量的初始化是在第一次访问的时候进行的。通过dispatch_once进行保护,使初始化只进行一次且是线程安全的。
  • static properties. 静态属性行为与全局变量相似,原因也相同。(There are no stored class properties in Swift, so class properties can’t be initialized and thus can’t have lazy initialization.??这句是什么意思)
  • Instance properties. 实例属性默认不是lazy的,可以在声明时用lazy标记,属性必须声明为var不能是let。

Lazy initialization通常用来实现单例。

Tuple

tuple当作函数参数传递时必须是常量。

Optional

ImplicitlyUnwrappedOptional,也是optional的,但是它的值可以直接用。

func realStringExpecter(s:String){}
var str: ImplicitlyUnwrappedOptional<String> = "how"
realStringExpecter(str)

var str! = "how" 效果一样

An implicitly unwrapped optional is still an Optional !

explicitly unwrapping an Optional contains nothing will crash!

var stringMaybe : String?
let s = stringMaybe! //crash

Optional Chains

To send a message safely to an Optional that might be empty, you can unwrap the Optional optionally.

var str: String?
let upper = str?.uppercaseString

If any of them is unwrapped optionally, the entire expression produces an Optional wrapping the type.

An assignment into an Optional chain with optional unwrapping returns an Optional wrapping Void.

let ok : Void ? = self.window?.rootViewController = UIViewController()
if ok != nil {
	//it worked
}

上一篇     下一篇