Swift 4.0 学习之基础摘要一
程序员文章站
2022-03-10 23:19:51
...
前提小知识:在Swift中,如果想要使用某一个类(cocoapods导入的三方库除外),是不用导头文件的,因为Swift新增了一个OC中没有的概念,叫“命名空间”。只要在同一个命名空间中的资源都是共享的,而且默认情况下,项目名称就是命名空间。
一:数据类型转换
在Swift中,没有隐式数据转换,所有的转换必须显示,举例如下:
//在OC中,所有数据都存在隐式转换
int a = 1;
int b = 1.1;//在OC中这么写,系统会自动转换成 b = 1;
float c = 1.1;
float sum = a + b + c;//在相加的等式中,虽然ab和c的数据类型不一样,但是系统也会自动转换成一样的去计算,这就是隐式转换
//但是在Swift中,没有隐式转换
let a: Int = 1
let b: Int = 1.1 //直接会报错
let c: Double = 1.1
let sum = a + b + c //这么写也会报错,因为类型不一样,必须显示的转换如下
let sum1 = a + b + Int(c) //所有数据必须转换成同一个类型才能进行计算
二:分支语句
在C和OC中,有一个非0即真的概念,但是Swift没有,举例如下:
int num = 10;
if (num) {
//在OC中,是会走到这里的,而且如果判断为真只执行一个语句的话,外面的大括号是可以去掉的
}
let num = 10
if num {
//但是在Swift里,首先if后面跟的条件可以不加小括号,但是后面的大括号绝对不能省略;
//第二点是,在Swift中,条件只能放bool值,取值只有true或false,如这里只放一个num就会报错
}
在Swift中,switch语句与OC的区别
1、在Swift中,break可以省略,不会穿透执行下面的语句
2、在Swift中,一个case下面有多条语句或者声明新的变量也不需要加大括号来确定作用域
3、在OC中,deafult位置可以随便写,并且可以省略。但是在Swift中,deafult只能写在最后,并且绝大部分情况不能省略
三:循环语句
OC中常用的普通for循环 for(int i=0;i<10;i++){}在Swift3.0已经移除掉了,现在Swift用的for in 循环很具有Swift特色,举例如下:
for var num in 0...10 {
//0...10表示包含头尾的0到10之间所有的整数
//0..<10表示包含头不包含尾的0到9之间所有的整数
//0...10这种条件区间内不能出现任何的空格
}
//如果不关心循环本身的索引,可以直接用下划线如下
for _ in 0...10 {
}
四:可选绑定
在Swift中,返回值或者数据类型后面加 ?表示可选类型,值可以为空,但是后面加 !的话,表示告诉编译器,这个是一定有值的,相当于强制解析,如果没有值的话,就会崩。这是前提。实际应用举例如下:
let url = URL.init(string: "http://www.baidu.com")
//正常写惯了OC的话,为了保证程序的稳定性,强制解析前一定会加判断,通常会这么写
if url != nil {
let request = URLRequest(url: url!)
}
//但是在工程中会有很多很多的可选类型,如果每个都这么写的话,看起来肯定不太优雅,所以Swift推出了一个可选绑定的写法
if let url = url {
let request = URLRequest(url: url)
}
五:数组和字典
数组和字典的创建和OC基本一致,不用写前面的@而已,但是遍历字典的时候,Swift由于有元祖这个东西在,改进的方便了一点,,举例如下:
let dictionay = ["一":1,"二":2]
//如果是OC的话,遍历这个字典会这么写,当然swift这么写也可以
for key in dictionay.keys {
print(key)
}
//但是Swift还有一种写法如下
for (k,v) in dictionay {//直接用一整个键值对来遍历字典,在循环里面能直接使用key和value
print(k)
print(v)
}
//在遍历数组的时候,Swift还提供了一种特别方便的方式
for (index,value) in array.enumerated() {
//index是下标,value是值
//这样使得遍历数组能写的更加简洁优雅
}
//创建可变字典的时候,如果向上面那样创建,那么value的类型只能是统一的,这样在实际应用中会有问题,所以可以这么创建:
var dic = [String: Any]()
//赋值,有这个key就直接赋值,没有这个key就会自动创建这个key然后赋值
dic["name"] = "马化腾"
//合并字典
for (key , value) in dictionay {
dic[key] = value
}
六:字符串
OC中的字符串是一个对象,继承于NSObject,但是Swift中的字符串是一个结构体,因此Swift中的字符串性能比OC中要高,实际应用举例如下:
var str1 = "zyt"
var str2 = "ssg"
//单纯拼接两个字符串直接加就可以
str1 += str2
//如果两个字符串类型不一致的时候,可以用\()来拼接,如下
let age = 25
let name = "zyt"
//目标 name = zyt ,age = 25
var str = "name = \(name) , age = \(age)"
//如果想要实现例如时间这种显示传入4显示04 04:03:25
var time = String.init(format: "%02d:%02d:%02d", 4,3,25)
字符串的处理必然要提起截取字符串,这在字符串的处理中属于比较常用的,但是Swift在处理截取字符串的时候没有一个很方便的系统api可以调用,所以目前来说,处理截取字符串大体有两种方式
首先第一种:通过转换成OC中的NSString来执行,举例如下:
var aaaa:NSString = "aljdflkasjflkas"//通过定义字符串类型为NSString来调用sub方法,也可这么写:var aaaa = "asldfjalksjf" as NSString 效果一样
let nnn = aaaa.substring(with: NSMakeRange(0, 4))
第二种方式:虽然通过上面那种方式没什么问题,但是总觉得就截一个字符串每次要这么转来转去,感觉总归有点low,因为Swift没有系统封装好这样截取字符串的api,那就自己封装一个吧,代码如下:
//写一个String的类扩展
extension String {
subscript(range: CountableClosedRange<Int>) -> Substring {//闭区间
let sIndex = range.lowerBound
var eIndex = range.upperBound
if sIndex > (count - 1) {
return ""
}else if eIndex > (count - 1) {
eIndex = count - 1
}
let start = index(startIndex, offsetBy: sIndex)
let end = index(startIndex, offsetBy: eIndex)
return self[start...end]
}
subscript(range: CountableRange<Int>) -> Substring {//开区间
let sIndex = range.lowerBound
var eIndex = range.upperBound
if sIndex > (count - 1) {
return ""
}else if eIndex > (count - 1) {
eIndex = count
}
let start = index(startIndex, offsetBy: sIndex)
let end = index(startIndex, offsetBy: eIndex)
return self[start..<end]
}
}
//然后就直接可以调用了,直接传入下标从几到几就可以了
let aaa = "alksdjflkajsf"
aaa[0...3]
aaa[1..<33]
aaa[22...222]//上面的方法已经做处理了,各种情况都能保证不会crash
七:函数
Swift的函数写法最基础的模式如下:
//基础表现形式
func 函数名(传入参数,多个用逗号隔开)-> 返回值类型 {
//如果没有返回值,可以填 Void,也可以 -> () ,也可以什么都不写,直接函数名(传入参数)后直接跟大括号
}
//实际应用中传入参数可以有以下三种写法
func sum(a: Int,y b: Int,_ c: Int) {
print(a + b + c)
}
// a就正常写法,y写b前面表示外参,外面用y,函数内用b,c前面加 _ 表示外面调用时不显示参数名,如下:
sum(a: 1, y: 2, 3)
八:闭包
说到闭包,用法跟OC的block是一样一样的,基本格式是 { ()->() in }
通常是放到函数的实参里,举一个实际应用的例子:
目标:创建一个scrollorView,上面有10个按钮,要求有一定的可复用性,可维护性,可扩展性。代码如下:
override func viewDidLoad() {
super.viewDidLoad()
let sc = creatScrollorView(creatNumber: { () -> Int in
return 10
}) { (index) -> UIView in
let btn = UIButton()
btn.setTitle("\(index)", for: .normal)
btn.backgroundColor = UIColor.yellow
btn.frame = CGRect.init(x: index * width, y: 0, width: width, height: 50)
return btn
}
//在Swift中,能不用self尽量不用self,self一般只在闭包中使用
view.addSubview(sc)
}
func creatScrollorView(creatNumber:() -> Int, viewIndex:(Int) -> UIView) -> UIScrollView {
let sc = UIScrollView.init(frame: CGRect.init(x: 0, y: 100, width: UIScreen.main.bounds.width, height: 100))
let count = creatNumber()
for i in 0..<count {
let subView = viewIndex(i)
sc.addSubview(subView)
sc.contentSize = CGSize.init(width: subView.bounds.width * CGFloat
}
return sc
}
上面说到闭包和OC的block用法一样,那么当类的对象持有闭包,闭包的代码块里持有类的对象的时候,必然也会出现循环引用导致对象无法被释放的问题。
在OC中,我们用一个弱指针去持有一个对象,然后在block的代码块里用这个弱指针去解决这个问题,代码如下:
__weak __typeof(&*self)weakSelf = self;
Swift其实也一样,写的更简单一点而已
weak var weakSelf = self
九: 懒加载
懒加载是一个在项目中特别常用的东西,在OC中,一般是通过重写getter方法来实现,但是在Swift里,多了一个叫 lazy 的修饰符,多么形象生动的命名。具体应用举例如下:
//在Swift中只需要通过 “lazy” + “=” + “闭包” 就可以实现懒加载
lazy var dataList:[Any] = {
//而且看这里,如果闭包是用来做懒加载的话,那么()-> () in return 全都可以省略
["zyt", 1, (4 , 5), ("name","zyt"), ["age":"25"]]
}()
十: setter–getter–方法
Swift的setter和getter方法跟OC的这两个方法大致一样,但是用法跟OC还是有区别的,比如上面说的懒加载。还有OC中常用的重写setter方法,在Swift里是这么用的:
var aaa: String? {
didSet {
//设置完之后调用这个方法,Swift中用这个方法来代替OC中的重写setter方法
}
}
//如果只重写了getter方法,那么这个属性称之为 计算型 属性
//相当于OC中的只读属性
//特点:计算型属性是不占用内存空间的
var age: Int {
get {
return 25
}
}
下一篇: Swift属性重载