姓名:谢艾芳 学号:16040410073
Swift基础知识4(接上一篇)
转自http://www.jianshu.com/p/02ab8c6c1f9f
〖嵌牛导读〗Swift 语言由苹果公司在 2014 年推出,用来撰写 OS X 和 iOS 应用程序,Swift语言让应用开发更简单、更快、更稳定,确保最终应用有着更好的质量
〖嵌牛鼻子〗Swift基础知识 Swift的编程技巧和方法
〖嵌牛提问〗如何简单学习Swift基本编程语言?
〖嵌牛正文〗
十一、类的使用
1、类的介绍和定义
Swift也是一门面向对象开发的语言,面向对象的基础是类,类产生了对象,class是Swift中的关键字,用于定义类
定义的类,可以没有父类.那么该类是rootClass,通常情况下,定义类时,继承自NSObject(非OC的NSObject)
class 类名 : SuperClass {
// 定义属性和方法
}
2、定义类的属性
Swift中类的属性有多种:存储属性,存储实例的常量和变量;计算属性,通过某种方式计算出来的属性;类属性,与整个类自身相关的属性
① 存储属性
存储属性是最简单的属性,它作为类实例的一部分,用于存储常量和变量,可以给存储属性提供一个默认值,也可以在初始化方法中对其进行初始化
// 给存储属性赋值
stu.age = 10
stu.name = "xiaoming"
stu.chineseScore = 89.0
stu.mathScore = 98.0
② 计算属性
计算属性并不存储实际的值,而是提供一个getter和一个可选的setter来间接获取和设置其它属性,计算属性一般只提供getter方法,如果只提供getter,而不提供setter,则该计算属性为只读属性,并且可以省略get{}
class Student : NSObject {
// 存储属性
var age : Int = 0
var name : String?
var chineseScore : Double = 0.0
var mathScore : Double = 0.0
// 计算属性
var averageScore : Double {
get {
return (chineseScore + mathScore) / 2
}
// 没有意义,因为之后获取值时依然是计算得到的
// newValue是系统分配的变量名,内部存储着新值
set {
self.averageScore = newValue
}
}
}
③ 类属性
类属性是与类相关联的,而不是与类的实例相关联,类属性的设置和修改,需要通过类来完成,类属性使用static来修饰
class Student : NSObject {
// 类属性
static var corseCount : Int = 0
}
// 设置类属性的值
Student.corseCount = 3
// 取出类属性的值
print(Student.corseCount)
④ 监听属性的改变
在OC中我们可以重写set方法来监听属性的改变,在Swift中可以通过属性观察者来监听和响应属性值的变化,通常是监听存储属性和类属性的改变,(对于计算属性,我们不需要定义属性观察者,因为我们可以在计算属性的setter中直接观察并响应这种值的变化)
willSet:在属性值被存储之前设置,此时新属性值作为一个常量参数被传入,该参数名默认为newValue,我们可以自己定义该参数名;didSet:在新属性值被存储后立即调用,与willSet相同,此时传入的是属性的旧值,默认参数名为oldValue;
willSet与didSet只有在属性第一次被设置时才会调用,在初始化时,不会去调用这些监听方法
class Person : NSObject {
var name : String? {
// 可以给newValue自定义名称
willSet (new){ // 属性即将改变,还未改变时会调用的方法
// 在该方法中有一个默认的系统属性newValue,用于存储新值
print(name)
print(new)
}
// 可以给oldValue自定义名称
didSet (old) { // 属性值已经改变了,会调用的方法
// 在该方法中有一个默认的系统属性oldValue,用于存储旧值
print(name)
print(old)
}
}
var age : Int = 0
var height : Double = 0.0
}
let p : Person = Person()
// 在赋值时,监听该属性的改变
// 在OC中是通过重写set方法
// 在swift中,可以给属性添加监听器
p.name = "xiaoming"
十二、类的构造函数
构造函数类似于OC中的初始化方法init方法,默认情况下载创建一个类时,必然会调用一个构造函数,即便是没有编写任何构造函数,编译器也会提供一个默认的构造函数,如果是继承自NSObject,可以对父类的构造函数进行重写
1、构造函数的基本使用
① 类的属性必须有值,如果不是在定义时初始化值,可以在构造函数中赋值
class Person: NSObject {
var name : String
var age : Int
// 重写了NSObject(父类)的构造方法
override init() {
name = ""
age = 0
}
}
// 创建一个Person对象
let p = Person()
② 初始化时给属性赋值
我们在创建一个对象时就会给属性赋值,可以自定义构造函数,如果自定义了构造函数,会覆盖init()方法,即不在有默认的构造函数
class Person: NSObject {
var name : String
var age : Int
// 自定义构造函数,会覆盖init()函数
init(name : String, age : Int) {
self.name = name
self.age = age
}
}
// 创建一个Person对象
let p = Person(name: "xiaoming", age: 18)
③ 字典转模型(初始化时传入字典)
例1
class Person: NSObject {
var name : String
var age : Int
// 自定义构造函数,会覆盖init()函数
init(dict : [String : NSObject]) {
name = dict["name"] as! String
age = dict["age"] as! Int
}
}
// 创建一个Person对象
let dict = ["name" : "xiaoming", "age" : 18]
let p = Person(dict: dict)
例2
利用KVC字典转模型
class Person: NSObject {
// 结构体或者类的类型,必须是可选类型,因为不能保证一定会赋值
var name : String?
// 基本数据类型不能是可选类型,否则KVC无法转化
var age : Int = 0
// 自定义构造函数,会覆盖init()函数
init(dict : [String : NSObject]) {
// 必须先初始化对象
super.init()
// 调用对象的KVC方法字典转模型
setValuesForKeysWithDictionary(dict)
}
}
// 创建一个Person对象
let dict = ["name" : "xiaoming", "age" : 18]
let p = Person(dict: dict)
十三、闭包
Swift闭包和OC中的block非常相似,OC中的block是匿名的函数,Swift中的闭包是一个特殊的函数,block和闭包都经常用于回调
1、OC中Block的使用
首先介绍一下OC中Block写法
① 第一种Block方式
@property (nonatomic, copy) void(^callBack)(NSString *name);
callBack 是block对象
回调方法
if(_callBack){
_callBack(name)
}
② 第二种Block方式
typedef void(^CallBack)(NSString *str);
@property (nonatomic, copy) CallBack callback;
callback是block对象
回调方法
if(_callBack){
_callBack(name)
}
③ 第三种Block方式
- (void)setUpWith:(void(^)(NSString *str))callback;
callback是block对象
回调方法
if(_callBack){
_callBack(name)
}
总结
Block的写法:
类型:
返回值类型(^block的名称)(block的参数)
值:
^(参数列表) {
// 执行的代码
};
2、Swift中闭包的使用
① 第一种闭包方式
var callBack : (()->())?
② 第二种闭包方式
func loadRequest(callBack : ()->()){
callBack()
}
总结
闭包的写法:
callBack: (形参列表) -> (返回值类型)
类型:(形参列表) -> (返回值类型)
值:
{
(形参) -> 返回值类型 in
// 执行代码
}
闭包的简写,如果闭包没有参数,没有返回值,in和in之前的内容可以省略
尾随闭包写法
① 如果闭包是函数的最后一个参数,则可以将闭包写在()后面
httpTool.loadRequest() {
print("回到主线程", NSThread.currentThread());
}
② 如果函数只有一个参数,并且这个参数是闭包,那么()可以不写
// 开发中建议该写法
httpTool.loadRequest {
print("回到主线程", NSThread.currentThread());
}
3、闭包的循环引用
如果在HttpTool中有对闭包进行强引用,则会形成循环引用,在Swift中检测一个对象是否销毁,可以实现对象的deinit函数
// 析构函数(相当于OC中dealloc方法)
deinit {
print("ViewController----deinit")
}
4、swift中解决循环引用的方式
① 使用weak,对当前控制器使用弱引用
但是因为self可能有值也可能没有值,因此weakSelf是一个可选类型,在真正使用时可以对其强制解包(该处强制解包没有问题,因为控制器一定存在,否则无法调用所在函数)
解决一
weak var weakSelf = self
httpTool.loadData {
print("加载数据完成,更新界面:", NSThread.currentThread())
weakSelf!.view.backgroundColor = UIColor.redColor()
}
② 可以写在闭包中,并且在闭包中用到的self都是弱引用
解决二
httpTool.loadData {[weak self] () -> () in
print("加载数据完成,更新界面:", NSThread.currentThread())
self!.view.backgroundColor = UIColor.redColor()
}
③ 使用关键字unowned
unowned 更像OC中的 unsafe_unretained,unowned 表示即使它原来引用的对象被释放了,仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil
解决三
httpTool.loadData {[unowned self] () -> () in
print("加载数据完成,更新界面:", NSThread.currentThread())
self.view.backgroundColor = UIColor.redColor()
}
十四、懒加载
swift中也有懒加载的方式,希望所有的对象在使用时才真正加载到内存中,和OC不同的是swift有专门的关键字来实现懒加载,lazy关键字可以用于定义某一个属性懒加载
1、懒加载普通方式
lazy var 变量:类型 = 系统类()
lazy var button:UIButton = UIButton()
2、懒加载升级方式
lazy var array : [String] = {
() -> [String] in
return ["xiaoming", "xl", "lisi"]
}()