一.swift基础
1.swift中没有了 .h/.m文件 只有一个 .swift文件 声明和实现都需要在同一个文件中
在swift中 没有非零既真的概念 只有true 和 false
() 标示初始化 也可以标示执行
在swift中 默认所有的文件共享 所有的对象的方法也是默认可以调用
命名空间: 在同一个项目下 叫做命名空间 在同一个命名空间下 所有的文件共享
swift 属性默认都是 强引用的
swift中 init 方法 就是构造方法,并且所有的构造方法 都叫 init
2.oc的
@interface ViewController : UIViewController
swift的
class ViewController: UIViewController { }
3.可选项
// 可选项: ?(有值吗) 1.有值 2.没有值(nil)
// 必选项: ! 程序员承诺 一定有值 同样也表示 强制解包
// 每添加一个 '!'的时候都需要思考为什么,安全吗 程序员承诺一定有值
//fatal(致命的) error: unexpectedly(意外的,不希望) found nil while unwrapping(解包) an Optional(可选的) value
/*
1.可选项在打印的时候 会自动带上 Optional(10)
2.可选项不能够直接参与运算
*/
//声明可选项 在类型后面追加 '?"
var a: Int?
4.常量和变量
let: 常量 一经赋值 就不能被更改
var: 变量 可以被更改
尽量使用常量 等到需要修改的时候在改成 使用 var 来修饰
数据类型
1.swift中 数据的类型是自动推导的 根据 '=' 右边的类型来去推断变量的具体类型
//option + click 最常用的热键值 没有之一
//swift 是一个类型极其苛刻的语言
2.可以提前声明类型: let 变量名: 类型
func demo7() {
let a=10
let b=12.4
//swift中 不支持 隐含形式的转换类型,直接a+b会报错哦
// let c = a+b
// print(c)
}
二.分支结构
swift中推荐使用的分支结构
1.switch case
1.每个case 分支 必须要有一段可以执行的代码
2.临时变量 的定义不需要加在 {} 中
3.OC中只能判断基本数据 swift中可以判断任意类型
4.可以同时case 多个选项
5.不需要写 break
func demo7() {
let m = "22200"
switch m {
case "18000", "22200":
print("高级工程师")
case "12000":
print("中级工程师")
case "8000":
print("初级工程师")
default:
print("你是猴子派来的吗")
}
}
/*
1.条件语句 没有 '()'
2.{} 不能省略
3.在swift中 没有非零既真的概念 只有true 和 false
*/
func demo2() {
let a = 10
// if a > 5
// print("haha")
// print("hehe")
if a > 0 {
print("大于0")
} else {
print("小于0")
}
}
2.??操作符: 快速判断可选项是否为 nil 如果为nil 给定默认值,在判断字符串 或者基本数据类型的时候用处很大
例如:tableView 数据源方法 list?.count ?? 0 这里list代表一个数组对象如果为nil那么给一个默认值0;
三.解决可选项问题
推荐两个方法 if let 和 guard let..else
if let 快速赋值 并且判断是否为空 不为空 才能够进入分支 意味着值就是一个必选项
func demo4() {
//url中包含中文 需要转义
let urlString = "http://www.douni.com?type"
if let url = NSURL(string: urlString) {
//当option + click string 时可以看到url是可选项
convenience init? 便利的构造函数 有可能能够实例化一个对象 有可能无法实例化一个对象(nil)
let request = NSURLRequest(URL: url)
print(request)
}
}
guard(守卫) let ... else 和if let的 作用刚好相反
能够减少一层分支嵌套
Xcode 7.0 swift2.0 才推出的语法
在项目使用的非常多 我自己也推荐这种写法
func demo5() {
let urlString = "http://www.douni.com?type=中国"
guard let url = NSURL(string: urlString) else {
//如果url 为nil 当前代码 就直接返回
return
}
//程序运行到这里 '守卫'的对象 就一定有值
let request = NSURLRequest(URL: url)
print(request)
}
四.循环
//2.现代写法 apple推荐的写法
// 0..<10 0 ~ 9 表示范围 不会向后包含
func demo1() {
for i in 0..<10 {
print(i)
}
}
// _ 表示忽略
func demo3() {
for _ in 0..<10 {
print("嘿嘿")
}
}
// 0...10 会向后包含 范围 0 ~ 10
func demo2() {
for i in 0...10 {
print(i)
}
}
五.字符串
OC : NSString 类 继承 NSObject
swift: String 结构体 更加高效,可以通过热键查看
//声明字符串
//没有 @
func demo1() {
let str: String = "叶良辰"
print(str)
//实例化一个字符串
var str1 = String()
str1 = "hello world"
print(str1)
}
//字符串的一些基本特性
func demo2() {
//1.长度 一个中文 字符串的长度 是3 个字节
let str = "你若安好"
//获取字节长度
let l = str.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)
//获取字符串的长度
// let l = str.characters.count
print(l)
//2.字符串的拼接
let str1 = "便是晴天"
// NSString stringWithFormat:"%@%@"
let str2 = str + str1
print(str2)
//字符串的判断
//isEqualToString
if str == str1 {
print("======")
} else {
print("!=====")
}
//ASC 值进行比较
let s1 = "abc"
let s2 = "xyz"
if s1 > s2 {
print("大于")
} else {
print("小于")
}
//字符串的转义
let i = 10
let str4 = "\(i)"
print(str4)
//字符格式化
// 1 23 45 拼接成 01:23:45
//format 格式化的类型 arguments: 可变参数
let h = 1
let m = 23
let s = 45
let str5 = String(format: "%02d:%02d:%02d", h,m,s)
print(str5)
}
func demo3() {
let str = "雷哥爱做地铁 , 地铁美女多"
//1.转化为 NSString
let str1 = str as NSString
//2.截取字符串
let subStr = str1.substringWithRange(NSMakeRange(11, 2))
print(subStr)
}
六.字典和数组
OC:NSArray [xxx]
swift: [元素]
let 修饰的数组 是不可变的数组
var 修饰的数组 是可变的数组
OC:字典 NSDictionary {}
swift: [key1 : value1, key2 : value2 ]
let 修饰的不可变的字典
var 修饰的可变的字典
func demo() {
//数组的定义 数组的类型也是可以自动推导
//数组中不推荐存放不同类型的元素 数组是通过索引来访问元素
let array = ["张三","lisi","王五",16]
//实例化一个数组
var array1 = [String]()
//添加元素
array1.append("赵六")
array1.append("张三")
print(array1)
//改
//通过索引来去修改元素
array1[0] = "郭敬明天见"
array1[1] = "夏洛特烦恼"
//删
// array1.removeFirst()
// array1.removeLast()
array1.removeAll()
//查
for str in array1 {
print(str)
}
//通过索引查询数据
//fatal error: Array index out of range
// let str = array1[1]
// print(str)
}
//数组的拼接
func demo1() {
var array1 = [String]()
let arr1 = ["夏洛特烦恼","郭敬明天见"]
let arr2 = ["哈哈","呵呵"]
array1 += arr1
array1 += arr2
//拼接
let arr = arr1 + arr2
print(array1)
}
//字典的基本操作
func demo2() {
//声明
let dict = ["name": "范冰冰","age" : 18,"title": "女神"]
//实例化字典类型
var dict1 = [String : NSObject]()
dict1["name"] = "张学友"
dict1["title"] = "歌神"
dict1["age"] = 18
// print(dict1)
//删
dict1.removeValueForKey("age")
//改
dict1["name"] = "周杰伦"
//查 在OC中遍历 字典 使用block
//()内键值的名字自己随意取 但是一个对应的是 键(key) 第二个对应是值(value)
for (key, value) in dict1 {
print(key, value)
}
let name = dict1["name"]
print(name)
}
七.函数
swift中调用本类的函数和属性 self可以省略 也可以加上 闭包内调用本类的函数和属性时 必须加 self
override func viewDidLoad() {
super.viewDidLoad()
//函数的调用
//函数的第一个参数名称可以省略
// sum(10, b: 20)
//
//
// let result = square(width: 10, height: 20)
// print(result)
demo3()
}
//函数没有返回值的三种写法
//1.没有返回值的第一种写法
func demo1() -> () {
print("哈哈哈")
}
//2.第二种写法 Void V要大些
func demo2() -> Void {
print("嘻嘻嘻")
}
//3.函数没有返回值的第三种写法
func demo3() {
print("黑hi额hi额")
}
//函数的外部参数
//外部参数 width是提供给调用方来进行使用的
//内部参数 a 是提供给函数内部使用的
func square(width a: Int,height b: Int) -> Int{
return a * b
}
//加法的函数
func sum(a: Int,b: Int) -> Int {
return a + b
}
八.闭包的基本使用
OC中block有哪些特点
1.可以定义为变量 block可以是一段提前准备好的可以执行代码块
let finishedCallBack = {
//就是一段可以执行的代码块
print("我就是回调执行的代码块")
}
2.可以当做函数的参数传递
loadData1("sisi", finished: finishedCallBack)
3.在需要执行的时候执行 可以产生回调的效果 (协议/代理,通知) block 可以有返回值 但是用的不多
//() -> () 闭包的最基本的类型 没有参数 没有返回值的闭包
//系统将闭包进行了简写
//必须是闭包参数是函数的最后一个参数 才可以进行闭包的简写 -> 将可执行的闭包挪动到参数体外面 ,形成 '尾'随闭包
//最多使用的还是这一中方
loadData("sisi") { (dataString) -> () in
//在闭包中智能提示 不是很好使 通常 需要生写
print(dataString)
}
//如果有闭包参数 建议 将闭包参数写在最后一个 可以写成尾随闭包
demo({ () -> () in
print("回调")
}, userId: "sisi")
}
func loadData(userId: String, finished: (dataString: String) -> ()) {
//耗时操作
dispatch_async(dispatch_get_global_queue(0, 0)) {
//在全局队列中执行耗时操作
print("开始加载数据")
//将结果回调到主线程
dispatch_async(dispatch_get_main_queue(), {
//执行回调
// print("===========")
//执行函数 其实闭包 知识一个匿名函数
// {
// print("回调的结果")
// }()
finished(dataString: "办证: 138XXXXXXX")
print("+++++++++++")
})
}
}
.....................................................................................
loadData1("思思") { () -> () in
print("回调的结果")
}
//返璞归真
loadData1("思思", finished: { print("回调结果") })
//比较残暴一种写法
loadData1("思思") {
print("回调的结果")
}
func loadData1(userId: String, finished: () -> ()) {
//耗时操作
dispatch_async(dispatch_get_global_queue(0, 0)) {
//在全局队列中执行耗时操作
print("开始加载数据")
//将结果回调到主线程
dispatch_async(dispatch_get_main_queue(), {
//执行回调
// print("===========")
//执行函数 其实闭包 知识一个匿名函数
// (): 标示初始化 也可以标示执行
// {
// print("回调的结果")
// }()
finished()
print("+++++++++++")
})
}
}
4.在block中 使用self 需要考虑 循环引用
函数只是 一种特殊闭包 在swift 中闭包才是老大(第一公民)
九.闭包的循环引用
//析构函数
deinit {
//和OC dealloc 方法类似
print("VC 886")
}
解决方式有两种[unowned self]和[weak self]但是[unowned self]当有网络延时的时候会崩
十.懒加载
//懒加载 什么时候调用 什么时候在初始化
//在swift 懒加载有特殊的写法
//就是一个可以被执行闭包这样可以在里面进行一些设置
lazy var nameLabel: UILabel = { () -> UILabel in
print("我懒了吗")
let l = UILabel()
return l
}()
//简单写法
lazy var ageLabel: UILabel = UILabel()
十一 单例
一般在音频,文件,网络请求,管理类都适合用单例
第一种 : oc的方法
在.m文件中实现
在桥接文件里导入头文件
去文件里使用单例
第二种方法
一般我们用下边这个方法就好,一句话搞定
//swift中单例对象很简单 最主要需要 依赖 let 一经赋值就不可以被更改
//简单写法
static let sharedTools: SoundTools = SoundTools()
十二.面向对象必选属性的构造
自定义对象一般作为一个模型保存数据 创建对象的类继承NSobject
如: let p=person()
我们创建一个name属性 var name: String 因为这样所以name 是一个必选属性,系统会报错解决方式有两种
第一种
var name: String = ""
第二种
初始值为nil 没有分配内存空间 延迟分配控件 什么时候用 什么分配内存控件 这种方式 是后面会大量运用到
var name: String?
3.第三种 构造方法解决,比较麻烦
override: 重写 覆盖, 父类已经存在这个函数 子类需要在父类的这个函数进行其他的一些操作
var name: String
//person的构造方法
override init() {
self.name = "李冰冰"
super.init()
//description 是NSobject的属性所以super.init之后
self.description
// self.name = "李冰冰"他是子类或本类的属性所以在super.init之前
let s =Student()
在创建一个子类对象的时候就会调用本身的init构造方法,而init构造方法中有[super init]就会往下调用父类的init构造方法一次类推形成遍历直到NSObject调用了init方法,对象才算构造完成,就可以使用"s"对象了这时对象"s"中就会拥有本类和父类的一切属性或方法
十三.函数的重载
我们可以看到在上述的构造方法中我们很容易把对象的属性写死导致参数不灵活所以可以利用函数的重载
函数的重载: 函数名相同 函数的参数的类型或者参数的个数不同 就形成了函数的重载
重载不仅仅发生在构造函数中
注意: 不能够和 重写混合记忆
重载有啥好处呢?
1.可以简化程序员记忆 wash(member:洗衣粉)
2.重载可以简化编译 操作符 减少大量使用不同的操作符 可以提升编译的效率
重载是面向对象的重要标记之一
class Person: NSObject {
//初始值都是 nil 等到super.init结束之后 还是没有值
var name: String
//age 整数类型也是nil oc整数的默认值是 0
//this class is not key value coding-compliant for the key age.'
//但是Int 在OC中是基本数据类型 不会主动调用 '初始化'方法 ,直接设置初始值之后,就会分配内存空间 一般基本数据类型都设初始值
var age: Int = 0
override init() {
self.name = "李冰冰"
self.age = 18
super.init()
}
//swift所有的构造函数 都是 init
/*
构造函数 有责任也有义务 确保 必选属性必须有值
*/
//函数的重载名字一样,参数类型或个属不同
init(name: String, age: Int) {
self.name = name
self.age = age
super.init()
}
十四 字典转模型 kvc
//字典转模型 使用KVC设置初始值
init(dict: [String : NSObject]) {
//kvc设置初始值 在运行时 间接给 '对象' 发送 setValue: forKey:
super.init()
//遍历字典中的键值对 给对象转发 setValue: forKey:
setValuesForKeysWithDictionary(dict)
}
//会检查 字典中的键值对应的属性的key 是否存在 如果存在就只直接赋值 不存在就会将消息转发给 setValue: forUndefinedKey:
override func setValue(value: AnyObject?, forKey key: String) {
super.setValue(value, forKey: key)
}
//如果没有重写 默认会调用父类的这个方法
//就是起过滤作用
override func setValue(value: AnyObject?, forUndefinedKey key: String) {
print(value,key)
// super.setValue(value, forUndefinedKey: key)
}
十五.便利的构造函数
override init() {
self.name = "李冰冰"
self.age = 18
super.init()
}
//便利 '构造函数'
/*
1. 可以返回nil
2.必须使用 '本类' 的构造函数来进行实例化 需要使用 'self' 来调用构造函数
3.遍历的构造函数本质上 是基于本类 '指定' 的构造函数(必须实例化对象) 来进行快速的扩展
*/
// let url = NSURL(string: "http://www.baidu.com")
convenience init?(name: String, age: Int) {
//通常 年龄需要做合法性的检查 让一个人年龄在一个合法区间内
if age < 0 || age > 1000 {
//不能够实例化该对象 必须是失败的构造器才能够返回 nil
return nil
}
//保证对象在 满足条件下 能够被实例化
//生写 指定构造函数
self.init(dict: ["name" : name, "age" : age])
}
//字典转模型 使用KVC设置初始值
init(dict: [String : NSObject]) {
super.init()
setValuesForKeysWithDictionary(dict)
}
十六.getter setter
//使用 didSet 重写set方法
var name: String? {
//值设置完毕之后会调用到didSet
didSet {
//通常在swift开中 使用这个方法来替代重写 set方法
//一般这里面操作 模型数据的绑定
print(name)
}
}
//只读属性 readonly
//在swift 中又特殊的叫法: 计算型属性
//必须依赖其他的属性进行计算,每次执行都会调用
var title: String? {
get {
//只读属性是没有存储空间
return "Mr" + (name ?? "")
}
}
//是否成年
// var isAdult: Bool {
// get {
// return age > 18
// }
// }
//计算型属性可以简写 可以将 getter省略掉
var isAdult: Bool {
return age > 18
}