苹果为什么要推出Swift
- 避免专利诉讼
- 吸引更多开发者
- 让应用开发更简单 、 高效 、 稳定
Swift 特色
- 苹果宣称 Swift 的特点是:快速、现代、安全、语法简单
- 可以使用现有的 Cocoa 和 Cocoa Touch 框架
- Swift 取消了 Objective-C 的指针及其他不安全访问的使用
- Swift 和 C 、 OC 可以混合使用
Swift 发展
- 2014 年 6 月 苹果在发布 Xcode 6.0 的同时发布了 Swift 1.0
- 2015 年 2 月 推出了 Swift 1.2 测试版
- 2015 年 6 月 苹果发布了 Xcode 7.0 和 Swift 2.0 测试版,并且 宣称在年底开源,对 iOS、OS X 和 Linux 都适用
- 从发布至今,苹果的每一个举措都彰显其大力推广 Swift 的决心
现状
- 目前App Store 有超过 15,000 个 app 是用 Swift 来开发的
- 目前国内有些公司的新项目已经直接采用 Swift 开发
- 目前很多公司都在做 Swift 的人才储备
学习资源
- 官方博客
https://developer.apple.com/swift/blog/ - 苹果官方Swift2.0说明书
https://itunes.apple.com/us/book/id1002622538 - 100个Swift必备tips,作者王巍
http://onevcat.com
Playground
- Playground 是 Xcode 6 推出的新功能
- 使用 Playground 的目的是为了方便:
- 学习 Swift 代码
- 验 Swift 代码
- 试 Swift 代码
- 并且能够可视化地看到运行结果,不需要将程序运行到模拟器或真机上
- 另外,使用 Playground只需要一个文件,而不需要创建一个完整的工程
快速体验
//: 输出hello world
print("hello world")
//: 下面来体验一下swift和OC的区别
//: 创建一个UIView
let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
//: 设置背景色
view.backgroundColor = UIColor.redColor()
//: 创建一个UIButton
let button = UIButton(type: UIButtonType.ContactAdd)
//: 设置按钮中心位置
button.center = CGPoint(x: 50, y: 50)
//: button添加到view里面
view.addSubview(button)
//: 在swift中访问属性和调用方法都是通过.来进行的
- 小结
- 语句末尾不用使用
;
- 在 Swift 中使用
print()
替代 OC 中的NSLog
- 在swift中访问属性和调用方法都是通过点语法
.
来进行的 - 在 Swift 中要实例化一个对象可以使用
类名()
的格式,与 OC 中的alloc/init
等价 - OC 中的
[[类名 alloc] initWithXXX]
,[类名 类名WithXXX]
在 Swift 中通常可以使用类名(XXX: )
找到对应的函数 - OC 中的
[UIColor redColor]
类方法,在 Swift 中通常可以使用类名.XXX( )
找到对应的函数
变量和常量
- let 定义常量,一经赋值不允许再修改
- var 定义变量,赋值之后仍然可以修改
/*
OC中:
定义变量: int a = 1;
定义常量: int const a = 1;
swift:
定义常量: let 常量名 = 值
定义变量: var 变量名 = 值
var 修饰的是可变的
let 修饰的是不可变的
*/
// 定义变量
var a = 10
// 修改变量
a = 20
print("a = \(a)")
// 定义常量
let b = 10
print("b = \(b)")
//b = 15
// 常量初始化后不能再修改
类型推导和类型装换
自动推导
- swift 对数据类型要求异常严格
- swift能够根据右边的代码,推导出变量的准确类型
- 如果要指定变量,可以在变量名后使用 : 类型
- Int类型分为好几种,Int8, Int16, Int32, Int64,因为类型严格,Int8和Int16不能进行运算,所以建议以后开发中都使用Int
重要技巧:Option + Click 可以查看变量的类型
如果要对不同类型的数据进行计算,必须要显式的转换
//: 自动推导
let a = 10
let b = 7.5
// binary operator '+' cannot be applied to operands of type 'Int' and 'Double'
// let c = a + b
// 将a转成Double类型
let c = Double(a) + b
// 将b转成Int类型
let d = a + Int(b)
// 定义一个float类型的常量, 定义时指定类型
let e: Float = 7.5
// 定义时指定类型 左右类型不匹配: 'Double' is not convertible to 'Float'
// let k: Float = c
// 先声明,后定义
var k: Int
// 在没有初始化之前不能使用, variable 'k' used before being initialized
//print(k)
k = 1
字符串 String
- 是一个结构体,性能高于NSString
- String 支持直接遍历
- String 目前具有了绝大多数 NSString 的功能
- String和NSString转换方便
定义字符串
- OC定义字符串
OC的字符串:
NSString *str = @"hello";
格式化字符串: [NSString stringWithFormat:@"%.02f", 3.14159]
swift中定义字符串:
var 变量名 = "hello"
- swift定义字符串
//: 定义字符串
var str = "我要飞的更高"
- 遍历字符串中的字符
// swift 2.0 中遍历字符
for c in str.characters
{
print(c)
}
- 字符串长度
// 返回实际字符的个数
let len2 = str.characters.count
字符串拼接
2个字符串直接相加
直接在 "" 中使用 (变量名) 的方式可以快速拼接字符串
// 字符串拼接
let hello = "Hello"
let world = "World"
let z = "个赞"
let i = 32
let helloworld = hello + " " + world
//: "\()" 把其他类型转成字符串
let title = "\(i) " + z
- 格式化字符串
- 在实际开发中,如果需要指定字符串格式,可以使用 String(format:...) 的方式
//: 格式化字符串,保留2位小数
let pi = 3.141592653
let fmtString = String(format: "%.02f", arguments: [pi])
eg. 网络请求返回一个地址,要判断是否是gif图片
let addr1 = "wwww.baidu.com/aa/bb/aa.Gif"
- 方法1: 统一转成小写
let addr4 = addr1.lowercaseString
- 判断地址是否是以gif结尾
addr4.hasSuffix("gif")
方法2: 截取字符串最后3位,判断是否等于gif
1.将String 转成NSString
let subString = (addr4 as NSString).substringWithRange(NSMakeRange(addr4.characters.count - 3, 3))
- 2.对比字符串是否相等
subString == "gif"
Optional可选
- 定义变量时,在类型后面添加一个
?
,表示该变量是可选类型 - 可选类型, 表示该变量
可能有值,也可能是 nil
,默认值是nil
- 在变量后添加一个
!
,可以强行解包
注意:强行解包必须要确保解包后的值不是
nil
,否则会报错
/*:
定义一个电话号码? int num = 10086; int num = 0;经常会忽略对没有电话号码的判断
swift推出可选类型(Optional), 表示一个变量或常量可能有值,也有可能没有值.时刻提醒我们变量可能没有值
可选类型的定义: 类型的后面加?
*/
// 定义可选类型
let num: Int? = 10086
// Optional(10086)
print(num)
// value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
// !表示强制拆包. 需要确定可选一定有值.
let sum = num! + 10
// 定一个可选,没有赋值
var num2: Int?
// 可选没有值用nil表示
print(num2)
// 可选没有值,进行强制拆包: fatal error: unexpectedly found nil while unwrapping an Optional value
//let sum3 = num2!
// 在对可选操作的时候需要判断是否有值.
if num2 != nil {
let sum3 = num2! + 10
print("sum3: \(sum3)")
} else {
print("可选没有值")
}
// 可选绑定, 当可选有值的时候,会把num2!赋值给 num3
if let num3 = num2 {
print(num3)
} else { // 如果num2没有值.
print("num2没有值")
}
if条件分支
- 在swift中没有非0既真、0为假,swift中
Bool
类型只有2个值:true
真,false
假 - 条件必须是
Bool
类型,或返回Bool
类型的表达式 - 条件可以省略括号
-
{ }
不能省略
/*
在C和OC中非0既真,0为假
int a = 1;
if (a)
{
NSLog(@"");
}
1. 在swift中没有非0既真、0为假,swift中Bool类型只有2个值:true 真,false 假
2. 条件必须是Bool类型,或返回Bool类型的表达式
3. 条件可以省略括号
4. { }不能省略
*/
var a = 1
//: type 'Int' does not conform to protocol 'BooleanType'
//if (a)
//{
// print(a)
//}
let iosNB = true
if iosNB
{
print("ios 牛x")
}
var pass = "及格"
var fail = "不及格"
let score = 59
//: 运算符结果返回Bool
if score > 60
{
print(pass)
}
else
{
print(fail)
}
//: 注意问号前一定要有空格, 条件也只能是Bool类型
var c = (score > 60) ? pass : fail
print(c)
循环
- OC for循环
//OC的for:
for (int i = 0; i < 5; i++)
{
NSLog(i)
}
- swift
for循环
常规写法
for var i = 0; i < 5; i++
{
print(i)
}
- swift 常用写法
// swift 常用写法
for i in 0...5
{
print(i)
}
- 范围运算符
// 范围运算符
// ... 闭合范围运算符 表示 a 到 b, [a, b] 0-5, 包含a,也包含b
// ..< 半闭合范围运算符 表示 a 到 b, [a, b) 0-4, 包含a,但是不包含b
省略下标
_ 表示忽略对应位置的值
for _ in 0...5
{
print("hello")
}
switch
判断学生分数
/*:
判断分数:
90-99: 优秀
80-89: 良好
70-79: 中等
60-69: 及格
60以下: 不及格
*/
let score = 99
// swift的 swith执行完一个case后默认不会执行下一个case
switch (score / 10)
{
case 9 :
print("优秀")
case 8 :
print("良")
case 7 :
print("中")
case 6 :
print("及格")
default:
print("不及格")
}
如果要执行下一个case
需要用fallthrough
关键字
switch (score / 10)
{
case 9 :
print("优秀")
case 8:
print("走我了吗?")
fallthrough
case 7:
print("良")
case 6 :
print("及格")
default:
print("不及格")
}
switch通过区间运算符匹配
//: switch通过区间运算符匹配
switch (score)
{
case 90...100 :
print("优秀")
case 70..<90 :
print("良好")
case 60..<70 :
print("及格")
default:
print("不及格")
}
匹配字符串
/*
Monday 星期一
Tuesday 星期二
Wednesday 星期三
Thursday 星期四
Friday 星期五
Saturday 星期六
Sunday 星期日
*/
//: 可以匹配字符串
let weekDay = "Tuesday"
switch weekDay
{
case "Monday":
print("星期一,该上班了")
case "Friday":
print("星期五,明天不上班")
default:
print("忙的忘记星期几了")
}
- 小结
-
switch
可以对Float
,Bool
,String
,Int
, 枚举 进行判断 - 不再需要
break
- 要处理所有可能的情况,不然编译器直接报错,不处理的条件可以放在
default
分支中
数组
- OC 中定义数组
/*:
OC中定义数组:
NSArray *arr = @[元素1, 元素1, 元素1];
在swift中定义数组:
var 数组名 = [元素1, 元素2, ...]
*/
- swift定义数组
//: swift定义数组
var array = ["bmw", "benz", "byd"]
var array1 = [3, 5, 7, 3, 2] // 类型是[Int],表示Int类型的数组,数组里面的元素都是Int类型
var array2 = ["liudehua", 54] // 类型是[NSObject],数组里面的元素都是NSObject类型,用的很少
- 初始化空数组
var array3: [Int] = []
var array4 = [Int]()
定义数组时指定数组类型
var array5: [Int] = [5, 6]
- 遍历数组中的所有元素(传统写法)
//: 遍历数组中的所有元素
for var i = 0; i < array1.count; i++ {
let n = array1[i] //取出数组中的某个元素
print(n)
}
- 遍历数组中的所有元素(swift写法)
//: 遍历数组中的所有元素
for n in array1 {
print("i = \(n)")
}
- 单独取出数组中的某个值
print(array[0])
print(array[1])
数组的常用操作
//: 取钱
var persons = ["liudehua", "zhangxueyou", "guofucheng"]
//: 添加元素到数组末尾
persons.append("liming")
//: 向数组中指定位置插入一个元素
persons.insert("chenglong", atIndex: 0)
//: 修改数组中元素的值
persons[0] = "fangzuming"
persons
//: 获取数组个数
persons.count
//: 删除数组最后位置的元素
persons.removeLast()
persons
//: 删除数组中指定位置的元素
persons.removeAtIndex(2)
persons
//: 删除数组中的所有元素
persons.removeAll()
// 判断数组是否为空
persons.isEmpty
/*
let修饰的数组是不可变数组或者说常量数组
var修饰的数组是可变数组
*/
let arr7 = [1, 2, 3]
//arr7[0] = 1
//arr7.removeAll()
//arr7.append(1)
// 数组合并
var arr8 = [1]
var arr9 = [2, 3, 5]
arr9 += arr8
print(arr9)
//: 数组不能越界访问,Array index out of range
//arr9[20]
元组
元组是由2个或以上元素组成的复合类型,而且元组中每个元素的数据类型都可以不同
元组定义好后不能添加或减少元素
var 修饰的元组可以修改元素的内容
let 修饰的元组不可以修改元素的内容
定义一个元组
//: 刘德华花5万美元买了一辆白色的宝马轿车
//: 定义元组类型为 (String, Int, String, String)
let car = ("liudehua", 50000, "white", "bmw")
- 元组访问
//:访问元组中的元素
car.0
car.1
- 定义元组时,指定元素名称
//: 定义元组时,指定元素名称
var car2 = (name: "liudehua", price: 50000, brand: "bmw", color: "white")
- 元组通过元素名称访问
//: 元组通过元素名称访问
car2.price
car2.brand
- 修改元组中元素的值
car2.brand = "byd"
- 元组分解(值绑定)
//: 元组的分解(值绑定)
let name1 = car1.name
let price1 = car1.price
let color1 = car1.color
let brand1 = car1.brand
//
let (name2, price2, color2, brand2) = car1
name2
brand2
//
let (name3, price3, color3, _) = car1
name3
字典
- 定义
- 同样使用 [] 定义字典
- let 不可变字典
- var 可变字典
/*
OC定义字典:
NSDictionary *dict = @{key1: value1, key2: value2, ...};
swift定义字典:
var 数组名 = [key1: value1, key2: value2, ...]
let 不可变
var 可变
*/
//: 定义字典
var dict1 = ["name": "liudehua", "age": 54] //[String : NSObject]
var dict2 = ["name": "liudehua", "nickName": "huazai"] //: [String : String]
- 定义空字典
var dict4 = [NSString: Int]()
var dict5: [NSString: Int] = [:]
- 字典的遍历
//: 遍历字典的所有key
for n in dict1.keys {
print(n)
// print(dict1[n])
}
//: 遍历字典所有value
for k in dict1.values {
print("k === \(k)")
}
//: 遍历字典
for n in dict6 {
// print(n)
// print(n.0)
// print(n.1)
}
//: 开发中用的最多的遍历字典的方式
//: k, v 可以随便写,前面是 key,后面是 value
for (k, v) in dict1 {
print(k + "--- \(v)")
}
//: 跳过不关心的值
for (_, v) in dict1 {
print("对key不关心--- \(v)")
}
字典常用操作
- 赋值直接使用 dict[key] = value 格式
- 如果 key 不存在,会设置新值
- 如果 key 存在,会覆盖现有值
var dict7 = ["name": "liudehua", "age": 53]
//: 访问字典中的元素
dict7["name"]
//: 当字典的key存在时,修改字典中的元素
dict7["age"] = 54
dict7
//: 当字典的key不存在时,会新增key和value
dict7["title"] = "king"
dict7
//: 删除字典中指定的key和对应的value
var dict8 = ["name": "liudehua", "age": 54, "height": 1.74]
dict8.removeValueForKey("age")
dict8
//: let修饰的字典不能改变 cannot assign through subscript: 'dict9' is a 'let' constant
let dict9 = ["name": "liudehua", "age": 54, "height": 1.74]
//dict9["name"] = "lisi"
枚举
- OC定义和使用枚举
/*:
OC 枚举:
enum Season {
Spring,
Summer,
Autumn,
Winter
};
//: 定义枚举变量
enum Season season = Spring;
*/
- swift定义枚举类型
//: 定义枚举类型,枚举的每个成员前面加case
enum Season {
case Spring
case Summer
case Autumn
case Winter
}
- 定义一个枚举变量
//: 定义一个枚举变量
var season = Season.Spring
//: 再次修改值的时候可以直接 .成员, 是因为类型推导.
season = Season.Summer
season = .Summer
print(season)
switch判断枚举类型
//: switch判断枚举类型
switch season {
case Season.Spring:
print("春天")
case Season.Summer:
print("夏天")
case Season.Autumn:
print("秋天")
case Season.Winter:
print("冬天")
}
//: 可以省略枚举名
var season2 = Season.Spring
switch season2 {
case .Spring:
print("春天")
case .Summer:
print("夏天")
case .Autumn:
print("秋天")
case .Winter:
print("冬天")
}
枚举成员类型
//: 定义枚举,成员类型为Int
enum Direction: Int {
case North = 0
case South = 1
case East = 2
case West = 3
}
//var direction = Direction.North
//: 使用初始值来定义枚举变量
var direction = Direction(rawValue: 1)
print(direction)
//: 可选绑定
if let dir = direction {
switch dir {
case .North:
print("北")
case .South:
print("南")
case .East:
print("东")
case .West:
print("西")
}
}
函数
- 函数的定义
func 函数名(形参名1: 形参类型1, 形参名2: 形参类型2, ...) `->` 返回值 {
// 代码实现
}
/*函数如果没有返回值:
1. 省略
2. -> Void
3. -> ()
外部参数名,作用能够方便调用人员更好地理解函数的语义
带外部参数名的参数列表格式:
(外部参数名1 形式参数名1: 参数类型1, 外部参数名2 形式参数名2: 参数类型2, ...)*/
- 函数定义和调用
//: 定义函数
func sum(a: Int, b: Int) -> Int {
return a + b
}
//: 调用函数, b表示外部参数名
sum(10, b: 20)
//: 没有返回值
func sayHello() -> () {
print("hello")
}
sayHello()
外部参数名
在形参名前再增加一个外部参数名,能够方便调用人员更好地理解函数的语义
swift2.0默认帮我们生成除第一个参数外的所有外部参数名
//: 为什么有外部参数名呢?
func addStudent(name: String, age: Int, number: Int) {
print("name = \(name), age = \(age), number = \(number)")
}
//: 如果没有外部参数名,我们很难判断每个参数的作用
//addStudent("liudehua", 54, 53)
//: 有外部参数名,每个参数的作用一目了然,swift2.0默认帮我们生成除第一个参数外的所有外部参数名
addStudent("liudehua", age: 54, number: 53)
//: 指定外部参数名
func addStudent2(stu_name name: String, stu_age age: Int, stu_number number: Int) {
print("name = \(name), age = \(age), number = \(number)")
}
addStudent2(stu_name: "liudehua", stu_age: 54, stu_number: 53)
- 函数返回元组类型
/*:
在c语言中要返回多个值:
1.传参数时传入指针,在函数内部修改该指针指向的值
2.返回一个结构体
3.返回数组
*/
//: 在swift中可以通过返回元组来方便的返回多个值
func getStudent() -> (String, Int, Int) {
return ("liudehua", 54, 53)
}
//: student是一个(String, Int, Int)的元组
let student = getStudent()
//: 可以通过.0 .1 来访问
student.0
student.1
//: 函数通过元组返回多个值,并且为元组中的元素取名成,方便调用
func getStudent2() -> (name: String, age: Int, num: Int) {
return ("liudehua", 54, 53)
}
let student2 = getStudent2()
student2.name
student2.age
闭包
- 闭包类似于 OC 中的 Block,是一段预先定义好的代码,在需要时执行
定义
- 体验UIView动画闭包
//: () -> Void 表示一个 `不需要参数,返回值为空` 的闭包类型
UIView.animateWithDuration(0) { () -> Void in
//
}
- 闭包表达式格式:
{ (形参名称1: 形参类型1, 形参名称2: 形参类型2, ...) -> 返回值 `in`
//要执行的代码
}
-
in
用于区分闭包定义和代码实现 - 定义闭包
// 定义闭包
var closure = { (text: String) -> Void in
}
- 调用闭包
// 调用闭包
closure("学习闭包")
闭包使用场景(回调)
- 模拟耗时操作
// 闭包的使用场景: 回调
// 在子线程执行完任务后通知调用者
func loadData(finished: (result: String) -> Void) {
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print("拼命加载数据: \(NSThread.currentThread())")
dispatch_async(dispatch_get_main_queue(), { () -> Void in
print(": \(NSThread.currentThread())")
// 通知调用者
finished(result: "获取到20条数据")
})
}
}
- 调用
loadData { (result) -> Void in
print("网络请求完成: \(result)")
}
闭包的简写
// 当闭包的参数和返回都为空时可以省略 () -> Void in
UIView.animateWithDuration(1) {
}
// 闭包是最后一个参数,可以把闭包放在()后面,尾随闭包
UIView.animateWithDuration(1) { () -> Void in
}
类的定义
- OC中的类
在OC中一个类包涵.h和.m两个文件
.h:
@interface 类名: 父类名
@end
.m:
@implement 类名
@end
实例化类:
类名 *变量名 = [[类名 alloc] init];
swift 定义类格式
()里面是空,表示调用类的默认构造函数 = [[类名 alloc] init];
swift中访问属性通过点语法来访问, 方法也是通过点语法来调用
继承和OC一样,通过 : 来继承, swift也只有单继承
class 类名: 父类名 {
//: 一些属性
//: 一些方法
}
实例化一个类:
var 变量名 = 类名()
注意:
1swift的继承和oc一样是通过:, swift也只有单继承
2.访问类的属性和调用类的方法都是通过.来进行的
3.覆盖父类方法, 需要加关键字 override
- 定义
Person
类:
//: 定义一个类, 没有继承任何类的类,称之为 基类,超类
class Person: NSObject {
// 名称属性
var name = "liudehua"
// 年龄
var age = 54
// 身高
var height = 1.78
// 体重
var weight = 70.0
// 方法
func sleep() {
print("累了,睡觉")
}
func eat() {
print("饿了,吃饭")
}
}
- 实例化
Person
类
// 实例化类Person
var p = Person()
// 访问属性
print(p.name)
// 修改属性
p.name = "zhangsan"
print("名称修改后:\(p.name)")
// 调用方法
p.sleep()
- 定义
Student
继承Person
//: 继承 和OC 一样通过 : 来实现继承
class Student: Person {
// 班级属性
var grade = "ios05期"
// 定义学习方法
func study() {
print("开开心心学习,高薪就业")
}
// 覆盖父类方法, 需要加关键字 override
override func sleep() {
print("学习累了,睡觉")
}
}
- 实例化Student
// 实例化Student
let s = Student()
print(s.grade)
// 调用Student的sleep
s.sleep()
类的属性
- oc中的属性:
- @property(noatomic, copy) NSString *name;
1.在
.h
声明getter
和setter
方法
2.在.m
实现getter
和setter
方法
3.在.m
生成 _成员变量
- 存数型属性: 存储数据
- 属性监视器: 当存储型属性发生改变的时候,通知我们属性发生了改变
willSet
: 在属性将要发生改变时调用
didSet
: 在属性已经发生改变时调用
计算型属性: 不存储任何数据,通过get方法来返回一个计算好的数据通过set方法来设置一个存储型属性的值,当只提供get方法时,称之为只读计算属性.必须要有get方法
计算型属性 相当于 OC 中的
@property
生成的getter
和setter
方法,只不过setter
方法没有给 _成员变量 赋值
@interface Person ()
@property (nonatomic, assign) CGFloat heightCM;
@end
@implementation Person
// getter
- (CGFloat)heightCM {
return ;
}
// setter
- (void)setHeightCM:(CGFloat)heightCM {
// 没有 _heightCM = heightCM
}
类属性: 不管创建多少个实例,都共享这个属性
定义:在类属性前面加
class
关键字,类属性只能是计算型属性访问方法:
类名.属性名
`存储型属性、计算型属性
class Person {
//: 存储型属性
var name = "liudehua"
//
//: 存储型属性,单位是m
var height = 1.74
//
//: 计算型属性
var heightCM: Double {
get {
return height * 100
}
set {
height = newValue / 100
}
}
//
//: 存储型属性
var age = 54
//
//: 存储型属性
var weight: Float = 70 {
willSet {
print("weight willSet")
}
didSet {
print("weight didSet")
}
}
//
//: 定义一个sleep方法
func sleep() {
print("person 累了, sleep...")
}
//
//: 定义一个eat方法
func eat() {
print("person 饿了, eat...")
}
}
// 实例化Person
var person = Person()
person.height
person.heightCM = 178
person.height
person.weight = 72
var person2 = Person()
//: person的weight属性和person2的weight没有关系,相互独立的.
person2.weight = 60
print(person2.weight)
类属性
//: 定义圆
class Circle {
//: 只要是圆就有圆周率,圆周率的值固定不变,不管创建多少个实例,都共享这个圆周率属性
//: 类型属性: 只读计算型属性
class var pi: Double {
return 3.141592653
}
//
var radius = 20.0
//
//: 周长,只读计算型属性
var perimeter: Double {
return 2 * Circle.pi * radius
}
}
//
//Circle.pi = 1
//
var pingpong = Circle()
pingpong.perimeter
//
pingpong.radius = 40
pingpong.perimeter
构造函数
自定义Car
对象
class Person {
var name: String
}
以上代码会报:“存储性属性没有初始化值”,原因是在swift中类实例化后,所有的存储型属性必须有值
解决方法1:定义属性时赋值
class Person {
// 直接赋值
var name: String = "liudehua"
}
// 实例化
var p1 = Person()
p1.name
// 实例化
var p2 = Person()
p2.name
//: 实例化出来对象 name属性都一样,显然不合理.
- 解决方法2:将对象属性类型设置为
Optional
class Person {
var name: String?
}
var p = Person()
p.name = "liudehua"
print(p.name)
//: 用可选的,打印出来都带Optional
- 输出结果:
Optional("liudehua")
- 有没有什么办法,在类的实例化过程中,给存储型属性设置指定的值?,实例化后直接拿来用.或者在类实例化时指定存储型属性的值
利用 init
函数为属性初始化
`
- 在swift中对象是通过构造函数来实例化的.构造函数的作用:在对象实例化过程中给所有的存储型属性设置初始值,并且执行必要的准备和初始化任务.
class Person: NSObject {
var name: String
var age: Int
//: 重写父类构造函数
override init() {
print("init")
name = "liudehua"
age = 22
}
}
重载构造函数
- swift 中支持函数重载,同样的函数名,不一样的参数类型
//: 重载构造函数
init(name: String, age: Int) {
self.name = name
self.age = age
}
子类构造函数
- 自定义子类时,需要在构造函数中,首先为本类定义的属性设置初始值
- 再调用父类的构造函数,初始化父类中定义的属性
- 如果子类没有去实现构造函数,会继承父类的构造函数
- 如果子类实现了构造函数,不会继承父类的构造函数
class Stuent: Person {
var grade: String
// 子类构造函数需要调用父类构造函数
// 需要先初始化子类属性,在调用父类构造函数
init(name: String, age: Int, grade: String) {
self.grade = grade
super.init(name: name, age: age)
}
}
convenience 构造函数
便利构造函数: 它是辅助性的构造函数.方便创建对象
- 默认情况下,所有的构造函数都是指定构造函数
Designated
-
convenience
关键字修饰的构造方法就是便利构造函数 - 便捷构造函数可以返回
nil
- 需要调用本类的一个指定构造函数
/// 方便创建ios05期学生
convenience init?(stuName: String, stuAge: Int) {
// 判断age是否合法
if stuAge < 0 || stuAge > 130 {
print("年龄不合法")
return nil
}
self.init(name: stuName, age: stuAge, grade: "ios05期")
}
构造函数小结
- 不需要
func
关键字.名称是固定的,都叫init
- 当类没有实现构造函数时,系统会添加一个默认的构造函数.
- 如果实现了构造函数,系统就不会添加默认构造函数
- 如果子类没有实现构造函数.会继承父类的构造函数
- 子类构造函数需要调用父类构造函数
- 需要先初始化子类属性,在调用父类构造函数
- 子类一旦实现了构造函数.就不会继承父类的构造函数
懒加载
在 iOS 开发中,懒加载是无处不在的
- 方法1
lazy var p = Person()
- 方法2
// 方法2, 需要指定p的类型
lazy var p: Person = {
let person = Person()
return person
}()
- 测试调用
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
p.name = "lisi"
print("p.name: \(p.name)")
}
-
Person
类
class Person: NSObject {
var name: String?
override init() {
print("初始化")
}
}