程序员

Swift 浅谈

2018-05-04  本文已影响14人  迎风起飞的猪
空合并运算符
var count:Int? = 10
var value:Int

/// 空合并运算符   第一个操作数必须为optional 如果不为nil责将进行拆包操作
print(count ?? 0)  和 三目运算符 print(count != nil ? count! : 0) 结果一样

结果为:10
元祖
/// 定义元祖
var student:(String,Int,Float) = ("kakaxi",20,185.0)
/// var stu:(name:String,age:Int,height:Float) = ("kakaxi",20,185.0)

print(student.0)
/// 将元祖进行分解   分解命名时使用_忽略命名字段
var (name,_,_) = student

print(name)

结果为:kakaxi
数组
声明一个十个元素相同的数组
var array = [String](repeating: "helllo world", count: 10)
var arrList = [0,1,2,3,4]

遍历数组的不同方式
for item in arrList {
    print(item)
}
0
1
2
3
4

for item in arrList.enumerated() {
    print(item)
}
(offset: 0, element: 0)
(offset: 1, element: 1)
(offset: 2, element: 2)
(offset: 3, element: 3)
(offset: 4, element: 4)

for index in arrList.indices {
    print(arrList[index], separator:"")
}

0
1
2
3
4
字典
var dicts:Dictionary<Int,String>
dicts = [1:"1",2:"2"]
print(dicts)

结果为:[2: "2", 1: "1"]
Set
集合(Set)

集合(Set)特点:无序、唯一性、集合操作、快速查找。
集合的数据显示和数组是一样的,所以必须显示的声明Set集合!不然!就是数组!
// 初始化A、B、C三个集合
var A:Set<String> = ["A", "B", "C", "D"]
var B:Set<String> = ["C", "D", "E", "F"]
var C:Set<String> = ["B", "B", "C"]

// 上面Array、Dictionary动态初始化有四种,这里面只有两种
var set1 = Set<String>()
var set2:Set<String> = []

// 集合的数量
A.count
// 集合第一个元素,因为集合的无序性,它的第一个元素没有意义
A.first
// 集合是否为空
A.isEmpty
// 向集合中插入一个元素
A.insert("C")
// 删除集合中的元素
A.remove("C")
// 判断集合中是否包含某个元素
A.contains("A")
// 遍历集合
for index in A {
    index
}
运算符
///通过~=运算符来检查某个数字是否包含在范围中
var range = 0...10
print(range~=8)   true
while和repeat-while 条件循环结构
当 i 大于等于10的时候跳出循环   
var i = 0
while i < 10 {
    print("while",i)
    i += 1
}
repeat while 循环
先执行循环体,在进行条件判断  和 OC 中的 do - while功能基本一致
var j = 0
repeat{
    print("while",j)
    j+=1
}while j < 10
流程跳转语句
swift中提供的流程跳转语句主要有:continue、break、fallthrough、return、throw、guard

continue: 语句用于循环结构中,作用为跳过本次循环,直接开始下次循环
break:中断语句,也可以用于循环结构中,和continue语句不同,break语句会直接中断包含它的循环结构
fallthrough:语句是swift中特有的一种流程控制语句,可以再中断语句中继续执行下面的语句

例如:
var i = 3
switch i {
case 1...3:
print("switch")
    fallthrough
default:
    print("default")
}
结果为:switch   default
如果不加fallthrough 结果为:switch

return: 用于返回结果值,或者用于提前结束无返回值类型的函数

throw: 语句用于抛出异常,抛出的异常如果不进行捕捉处理,也会使程序中断

guard - else: 是Swift2.0之后新加入的一种语法结构,Swift团队创造它的目的在于是代码结构和逻辑更加清晰

func normalFunc(param:Int){
    if param <= 0 {
        return
    }
    print(param)
}

func fuardFunc(param:Int){
    guard param > 0 else {
        return
    }
    print(param)
}

声明函数
有参数有返回值
func compare(param1:Int,param2:Int)->Int {
    return param1 + param2
}

var add = compare(param1: 10, param2: 20)
print(add)   30

func search(searchID:Int)->(success:Bool,data:String){
    let reust = true
    let data = "数据实体"
    return(reust,data)
}

if search(searchID: 1000).success {
    print(search(searchID: 1000).data)   数据实体
}

函数的参数可以传也可以不传(设置默认值)
func myFunc(param1:Int,param2:Int = 10)->Int {
    return param1 + param2
}

print(myFunc(param1: 8))   18
print(myFunc(param1: 10, param2: 40))    50

函数可以多参数,也可以多个不确定参数
在参数后面添加...   
func funcParams(param:Int...)->Int{
    var sum = 0
    for count in param {
        sum+=count
    }
    return sum
}
print(funcParams(param: 10,20,30,40,50))   150

声明一个函数变量
var addFunc:(Int...)->Int
addFunc = funcParams
print(addFunc(100,200))   300

函数重载    相同方法名   参数返回值不同
func addFunc(param1:Int,param2:Int)->Int{
    return param1 + param2
}
func addFunc(param1:Double,param2:Double)->Double{
    return param1 + param2
}
func addFunc(param1:String,param2:String)->String{
    return param1 + param2
}
闭包
闭包标准结构:
{(参数列表)-> 返回值 in 闭包体}
首先闭包最外层由大括号包围,内部由闭包关键字in来进行分割,关键字in前面为闭包结构的参数列表和返回值,其书写规则与函数一致,in关键字后面为闭包体,用于实现具体功能

let closures = {(param:Int)->Int in
    return param * param
}
自定义运算符
prefix operator ++
prefix func ++(param:Int)->Int
{
    return param + 1
}
枚举
enum Season {
    case spring
    case summer
    case autumn
    case winter
}
let season = Season.spring

func switchFunc(){
    switch season {
    case .spring:
        print("spring")
    case .summer:
        print("summer")
    case .autumn:
        print("autumn")
    default:
        print("winter")
    }
}

switchFunc()   spring
结构体
swift 既可以声明属性也可以定义方法

struct Car {
    var price:Int
    var brand:String
    var petrol:Int
    mutating func Drive(){
        if petrol > 0 {
            print("driving")
        }else{
            print("drived")
        }
    }
}

var car = Car(price: 100000, brand: "宝马", petrol: 10)
car.Drive()   //  driving
在创建类时,使用final关键字  其类不可以被继承  
使用final声明属性时,其属性不可以被子类使用
指定构造方法与遍历构造方法
对于类来说,构造方法有指定构造方法和便利构造方法之分。 指定构造方法的官方名称为Designated,遍历构造方法为Convenience。
 指定构造方法不需要任何关键字修饰,便利构造方法需要使用Convenience关键字来修饰。
关于指定构造方法和便利构造方法,Swift语言中有这样的规定:
1.  子类的指定构造方法中必须调用父类的指定构造方法。
2.  遍历构造方法中必须调用当前类的其他构造方法。
3.  遍历构造方法归根结底要调用到某个指定构造方法。

// 创建一个类作为基类
class BaseClass {
    // 提供一个指定构造方法
    init() {
        print("baseClass Designted")
    }
    
    // 提供一个便利构造方法
    // 便利构造方法必须调用当前类中的其他构造方法,并最终调用到指定构造方法
    convenience init(param:String) {
        print("BaseClass Convenience")
        /// 进行指定构造方法的调用
        self.init()
    }
    
}

/// 创建一个BaseClass的子类
class SubClass: BaseClass {
    // 覆写指定构造方法中必须调用父类的指定构造方法
    override init() {
        super.init()
    }
    
    // 提供两个便利构造方法
    convenience init(param:String) {
        // 最终调用到某个指定构造方法
        self.init()
    }
    
    convenience init(param:Int) {
        // 调用一个便利构造方法
        self.init(param: "Swift")
        
    }
}

var obj = SubClass()
print(obj)     // baseClass Designted   conditation.SubClass
引用计数
Swift中语言中的数据传递分为两种,即值类型的数据传递和引用类型的数据传递

对于值类型的数据传递,其采用的是完全复制的原理,因此原数据的销毁与内存的释放并不会影响新数据,
新数据占用的内存会在它本身作用域结束时释放。

if true {
    var a = 0
    if true {
        var b = 1
        a = b
    }
    // 此时变量b所占内存被释放
}
// 此处变量a所占内存被释放

引用数据类型的数据传递就复杂一些,我们知道引用类型的数据传递并不会完全复制原数据,
而是通过要引用的方式对原数据进行访问,因此无论一个类实例被多少个变量所承载,其真正所访问的内存都是同一个地方。
if true {
    var a = TestClass()
    if true {
        var b = a
    }
    // 此处变量b已经不存在,但是TestClass实例依然占用内存, 没有释放
}
// 此处变量a已经不存在,也没有其他变量引用TestClass实例,该实例将调用deinit方法,其所占内存被释放
循环引用及其解决方法
循环引用一直是初级开发者编程的噩梦。对类实例进行不当的引用会造成内存泄露,内存泄露积累到一定程度就会给应用程序带来灾难性的后果。

class ClassOne{
    deinit {
        print("ClassOne deinit")
    }
}

class ClassTwo{
    /// ClassTwo 类中有一个ClassOne类的属性
    var classOne:ClassOne?
    init(classOne:ClassOne?) {
        self.classOne = classOne
    }
    deinit {  /// 析构方法  相当于OC中的dealloc
        print("ClassTwo deinit")
    }
}

var classOne:ClassOne? = ClassOne()
var classTwo:ClassTwo? = ClassTwo(classOne: classOne)
/// 此时ClassTwo类中的classOne属性依然在引用classOne实例,因此classOne实例所占内存没有释放
classOne = nil
/// 此时classTwo 被释放,classTwo中的属性也都被释放,不在有谁引用classOne,classOne实例也被释放
classTwo = nil

结果为:
   ClassTwo deinit
   ClassOne deinit   

**上述代码十分健康,两个类都被释放**


class ClassOne{
    var cls:ClassTwo?
    deinit {
        print("ClassOne deinit")
    }
}

class ClassTwo{
    /// ClassTwo 类中有一个ClassOne类的属性
    var cls:ClassOne?
    init(cls:ClassOne?) {
        self.cls = cls
    }
    deinit {
        print("ClassTwo deinit")
    }
}

var classOne:ClassOne? = ClassOne()
var classTwo:ClassTwo? = ClassTwo(cls: classOne)
classOne?.cls = classTwo

classTwo = nil
classOne = nil

**上述两个类都没有被释放,代码中已将将classOne和classTwo都置为nil,但其所占据的内存将无法释放,这便是循环引用最常见的场景**

Swift 语言中提供了弱引用关键字(weak)来处理这样的问题;weak 关键字的作用是在使用这个实例的时候并不保有次实例的引用
(普通的引用类型数据在传递时会使实例的引用计数加1,使用weak关键字修饰的引用类型数据在传递时不会使引用计数加1)

将ClassOne中的属性 使用weak 声明:
  weak var cls:ClassTwo?
结果为:
     ClassTwo deinit
     ClassOne deinit   

扩展:
**
弱引用还有一个特点,其职能修饰Optional类型的属性,被弱引用的实例释放后,这个属性会被自动设置为nil,那么问题来了,如果开发中使用到的属性是非Optional值类型的,又恰巧出现了循环引用的场景,开发者该如何处理呢?其实Swift语言中还提供了一个关键字(unowned 无主引用)来处理非Optional值类型属性的循环引用问题。
**
上一篇 下一篇

猜你喜欢

热点阅读