方法
- 实例方法
- 在实例方法中修改值类型
struct area { var length = 1 var breadth = 1 func area() -> Int { return length * breadth } // 在方法结束时给隐含属性self,赋值一个全新的实例,替换原来的 mutating func scaleBy(res: Int) { length *= res } }
- 在实例方法中修改值类型
- 类方法
- 结构体和枚举用
static声明,类用class声明
- 结构体和枚举用
下标脚本
- 使用
subscript关键字,显示声明入参和返回值类型 - 使用
subscript后,实例可以x[0]的形式,对实例进行访问和赋值struct SomeStruct { var decrementer: Int subscript(index: Int) -> Int { get { return decrementer / index } set { self.decrementer = newValue } } } let division = SomeStruct(decrementer: 100) print("100 除以 9 等于 \(division[9])")
Swift构造过程
- 使用
init()方法构造,不需要返回值 - 可以再定义
init()方法时,提供构造参数struct SomeStruct { var decrementer: Int // _下划线描述外部参数名,调用的时候可以省略 init(_ decrementer: Int) { self.decrementer = decrementer } } let division = SomeStruct(12) - 如果你在定义构造器时没有提供参数的外部名字,
Swift会为每个构造器的参数自动生成一个跟内部名字相通的外部名 - 可选属性,初始值为nil
- 常量类型的值可以再定义它的类的构造过程中修改,不能再子类修改
- 默认构造器将创建一个所有属性值都设置为默认值的实例
struct的逐一成员构造器struct SomeStruct { var decrementer: Int var index: Int } var area = SomeStruct(decrementer: 10, index: 8)- 值类型的构造器代理
- 构造器可以通过其他构造器来完成实例的部分构造构成
struct Size { var width = 0.0, height = 0.0 } struct Point { var x = 0.0, y = 0.0 } struct Rect { var origin = Point() var size = Size() init() { } init(origin:Point, size: Size) { self.origin = origin self.size = size } init(center: Point, size: Size) { let originalX = center.x - size.width / 2.0 let originalY = center.y - size.height / 2.0 self.init(origin: Point(x: originalX, y: originalY), size: size) } } - 类的指定构造器
init(),每一个类都必须拥有至少一个指定构造器 - 类的便利构造器
override convenience init(no1: Int) - 子类不会继承父类的构造器
class SuperClass { var name: String init(name: String) { self.name = name } convenience init() { self.init(name: "匿名") } } let main = SuperClass(name: "Runoob") let main1 = SuperClass() // name是"匿名" init?(name: String)或者init!(name: String)可失败构造器enum TemperatureUnit { case Kelvin, Celsius, Fahrenheit init?(symbol: Character){ switch symbol { case "K": self = .Kelvin case "C": self = .Celsius case "F": self = .Fahrenheit default: return nil } } }- 子类覆盖一个可失败构造器
Swift析构过程
deinit- 类实例被释放之前,析构函数立即被调用
- 只有类类型有
deinitvar counter = 0 //引用计数 class BaseClass { init() { counter += 1 } // 每个类只有一个析构函数,不带任何参数和括号 deinit { counter -= 1 } }
可选链
- 使用
if语句判断是否可以调用//调用成功返回Void,调用失败返回nil if ((john.residence?.printNumberOfRooms()) != nil) { print("输出房间号") } else { print("无法输出房间号") } - 使用可选链调用下标脚本
// 问号在方括号前面 if let firstRoomName = john.residence?[0].name { print("第一个房间名 \(firstRoomName).") } else { print("无法检索到房间") } - 访问可选类型的下标
var test = ["Dave": [87,89]] test["Dave"]?[0] = 91
ARC
- 循环引用
- 两个类实例保持对对方的强引用
- 解决--弱引用和无主引用
class Person { var apartment: Apartment? deinit { print("person") } } class Apartment { // 弱引用 weak var tenant: Person? //无主引用 // unowned var tenant: Person? deinit { print("apartment") } } var runoob: Person? var number73: Apartment? runoob = Person() number73 = Apartment() runoob?.apartment = number73 number73?.tenant = runoob runoob = nil number73 = nil- 闭包循环引用
- 如果再闭包中引用
self,这个闭包必须是lazyclass HTMLElement { let name: String let text: String? // 如果lazy属性是闭包调用的结果,那么不考虑循环引用问题 lazy var getAge: String = { self.name }() // // lazy var asHTML: () -> String = { // // unowned 方式,self是assign方式,有可能出现野指针 //// [unowned self] in // 闭包和捕获的实例总是同时销毁时,用无主引用 // return self.name // // weak方式 //// [weak self] in // 当捕获的引用有可能会是nil时,将闭包内的捕获定义为弱引用 //// return (self?.text ?? "") // // // // } init(name: String, text: String? = nil) { self.name = name self.text = text } // deinit { print("\(name) is being deinitialized") } } var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello world") print(paragraph!.getAge) paragraph = nil
- 如果再闭包中引用
@escaping- 非逃逸闭包,闭包调用发生在函数结束之前
- 逃逸闭包,闭包调用发生在函数结束之后,闭包调用逃离了函数的作用域,需要用
@escaping声明 - 逃逸闭包不可以捕获
inout类型的参数
typealias Closure = () -> () func someMethod(block: Closure) { block() } var globalClosure : Closure? // 逃逸闭包 func escapingMethod(block: @escaping Closure) { globalClosure = block } // 逃逸闭包 func escapingMethod2(block: @escaping Closure, value: inout Int) { DispatchQueue.global().async { // 逃逸闭包不可以捕获inout参数 // func plus() { // value + 1 // } block() } }
类型转换
is- 检查实例是否属于特定的类型
class Subjects { } class Maths: Subjects { } class Chemistry: Subjects { } var p: Subjects p = Maths() if p is Subjects { print("Maths") }
- 检查实例是否属于特定的类型
asas子类向父类转let sub = Subjects() let mat = Maths() // 子类向父类转 let asMat = mat as Subjectsas用在switch语句中,检测对象类型,对对象类型处理let sa = [Chemistry(), Maths()] for item in sa { // 用在switch语句中,检测对象类型,对对象类型处理 switch item { case _ as Maths: print("Maths") case _ as Chemistry: print("Chemistry") default: break } }
as?- 向下转型(
DownCasting),父类向子类转换 - 转换不成功时返回
nil, 转换成功时返回的是可选类型let sa = [Chemistry(), Maths()] for item in sa { if let show = item as? Chemistry { print("化学 \(show)") } else if let example = item as? Maths { print("\(example)") } }
- 向下转型(
as!- 向下转型(
DownCasting),父类向子类转换 - 转换不成功时,报 runtime 运行错误。
let sub: Subjects = Maths() let mat = sub as! Maths
- 向下转型(
Any- 可以表示任何类型,包括方法类型
var exaAny = [Any]() exaAny.append(2) exaAny.append("string") exaAny.append(2.3) for item in exaAny { switch item { case let someInt as Int: print("\(someInt)") case let someString as String: print("\(someString)") case let someDouble as Double: print("\(someDouble)") default: print("none") } }
- 可以表示任何类型,包括方法类型
AnyObject- 可以代表任何
class类型的实例var exaAnyObject = [AnyObject]() exaAnyObject.append(Subjects()) exaAnyObject.append(Maths())
- 可以代表任何