swift 基础(一)

swift 的变量都是集成结构体,并且结构体里边和实现了很多的方法

swift 不允许基本属性为空(必须有一个不为空的初始值),所以引入了可选类型

:可选类型

就是一个盒子,里边装这数据

:强制解包

脱掉盒子,拿到里边的数据

if 或者guard 可选项绑定解包

let a : Int? = 10 
if let b = a {
  // 如果a 解包 == b
  print(b)
}else {
  //解包失败
}
// guard 默认是flase(和if 相反)
guard let b = a else{
  // 如果a 解包 == b
  print(b)
}

??:空合运算符

// 底层是一个自动闭包
//如果b不为空,把b赋值给a,如果b为空,把c赋值给a
let a = b  ??  c
//> 注意:b 必须是可选类型
// b和c的存储类型必须相同
// a的类型取决于c 的类型,如果c 为可选类型,那么a为可选,如果c为值,a也为值
let b : Int?  = 10 
let c = 1
let a = b ?? c // a = 10 强制b解包,赋值给a

let b : Int?  = nil
let c = 1
let a = b ?? c // a = 1 

//空合运算符解包(解包成功就赋值,否则赋值为o)
let a : Int? = 10 
let b = a ?? 0 

枚举:

// 普通
enum Direction {
  case north //成员值
  case south
  case east
  case west
}
// a(enun) 一个字节保存(0,1,2,3) 
let a = .north

enum Score {
  case points(Int) // 关联值 (成员值和其他类型的关联存储在一起)
  case grade(String)
}
// b(enun) 16个字节保存(int = 8  string = 8)
// 关联属性保存在enum 内存中 
let b = Score.points(98)

enum Poker : String {//原始值类型
  case a = "A" // 原始值(相同类型的默认值赋值给关联值(默认关联成员值))
  case b = "B"
}
// c(enun) 1个字节保存(1,2)
// 原始值其实就是一个计算属性,内部是以set来实现的,所以不会占enum 的内存
let c  = Poker.a
let d = Poker.a.rawValue//c.rawValue

结构体

struct Point {
  var x : Int
  var y : Int
}
// 结构体默认有一个init 方法
// a (struct) 占 16 字节
var a = Point(x : 10, y : 20)
//下边的方法不行(变量必须包含一个初始值)
var a = Point(x : 10)
var a = Point(y : 20)
var a = Point()

struct Point {
  var x : Int = 10
  var y : Int = 20
}
// 结构体默认有4个init 方法
//下边的方法都可以
var a = Point(x : 10, y : 20)
var a = Point(x : 10)
var a = Point(y : 20)
var a = Point()

// 下边2中写法相同(系统默认添加init初始化器)
struct Point {
  var x : Int = 10
  var y : Int = 20
}

struct Point {
  var x : Int 
  var y : Int
  init(){
    x = 10
    y = 20
  }
}

class Point {
  var x : Int = 10
  var y : Int = 20
}
// 如果类有初始化值就,默认创建一个init方法
// 如果没有初始值,默认一个init 方法都没有
// a (class) 占 32 字节,保存在堆上 前8个字节保存指向类型的信息,后8个字节是引用计数,再后边是x 和 y 各占8字节
var a = Point()
//下边的方法不行(类没有)
var a = Point(x : 10)
var a = Point(y : 20)
var a = Point(x : 10, y : 20)

类和结构体的区别

  1. 结构体(枚举) 是值类型 而 类是引用类型(指针类型)
  2. 值类型保存在栈里边,而引用类型保存在堆里边
  3. 值类型赋值,采用的是深拷贝(在swift 标准库中,sring,arr,dic 等如果指没有修改,采用的就是浅拷贝)
  4. 类可以继承,而结构体不可以

闭包表达式

func sum (_ vi: Int, _v2: Int) -> Int{
  return v1 + v2
}
//等价下边这个,return 一行可以省略
func sum (_ vi: Int, _v2: Int) -> Int{ v1 + v2}

// 使用闭包表达式
let fn = {
   (_ vi: Int, _v2: Int) in { v1 + v2}
}
fn(10, 20)

//闭包精简过程
func exec(v1: Int, v2:Int, fn: (Int, Int) -> Int){
  print(fn(vi, v2))
}
//调用
exec(v1:10, v2:20, fn: {
  (vi: Int, v2: Int) -> Int in return  v1 + v2
})
exec(v1:10, v2:20, fn: {
  vi, v2  in return  v1 + v2
})
exec(v1:10, v2:20, fn: {
  vi, v2  in  v1 + v2
})
exec(v1:10, v2:20, fn: {
    $0 + $1
})
//尾随闭包(当最后一个参数是闭包表达式,可以放到函数调用的外边)
exec(v1:10, v2:20)  {
    $0 + $1
}

闭包

当闭包表达式引用了捕获了外部变量,就把这个表达式+变量的组合叫做闭包

typealias Fn = (Int) -> Int
func getFn () -> Fn{
  var a = 0
  func plu(_ i: Int) -> Int{
    a += i
    return a
  }
  return plu
}//plu + a 形成闭包
//a为局部变量,保存在栈里边,fn(1) 执行完成,就释放了;那么为什么fn(2) = 3
// 闭包为了延长局部变量的生命周期,把a重栈空间拷贝到堆空间
// fn 占16字节,前8个字节是plu的地址值,后8个是a堆空间的地址值(如果没有捕获,后边都是0)
//当调用plu 的时候,会把a的地址值传进去
var fn = getFn()
print(fn(1)) // 1
print(fn(2)) // 3
var fn1 = getFn()
print(fn1(1)) // 1
print(fn1(2)) // 3

//自动闭包 @autoclosure
func geta  (_ v1: Int, _ v2:  @autoclosure () -> Int) ->Int{
  return v1 > 0 ? v1 : v2()
}
//自动把 20 变成了闭包 :geta(10, {20}) 
geta(10, 20) 

属性

分类:

1.实例属性:使用对象调用
存储实例属性:相当成员变量,类和结构体可以定义而枚举不可以
计算实例属性:就是方法,不占用内存,枚举也可以定义

2.类型属性:使用类调用的(在class 也可以使用class 修饰,线程安全)
存储类型属性:整个程序运行过程中只有一份内存(static 修饰)
计算类型属性:static 修饰

//一般情况下,使用计算属性就是因为计算属性和存储属性存在魔种有关系
class c {
//存储属性
  var a :Double
//计算属性:不能使用let,因为要改变。
//可以只有get 方法(但是这样也不能使用let),不能只有set方法
  var b : Double {
    set {
      a = newValue / 2
     }
    get {
      a * 2
     }
  }
}

延迟属性lazy

在第一次使用的时候初始化

class text {
// lazy 不能使用let(let 必须在初始化之前有初始值)
// 多线程调用lazy 属性,有可能初始化多次
  lazy var a: Int
}
var a = text()//没有初始化a, a.a 的时候调用

属性观察器

非lazy 可以添加
在初始化的时候不会触发属性观察器

class text {
   var a: Int{
    willSet{
      print(newValue)
    }
    didSet{
      print(oldValue, newValue)
    }
  }
}

存储类型属性

class Car {
    static var count = 1
}
// 和全局变量一样
// 默认为lazy,并且可以为let
// 第一次赋值( count = 1)的时候,底层调用了dispath_one 初始化
Car.count = 10

方法

实例方法:对象调用的方法
类型方法: 类型调用的方法(结构体和class)

class Car {
    static var cout = 0
    init() {//实例方法
    }
    //类型方法
    static func getCount() ->Int{ cout }
}
var car = Car()
Car.getCount()

struct Car {
    var a = 0
    //结构体(或枚举)不能在方法里边修改变量,class 可以
    //add mutating 就可以了
    mutating func text(){
        a = 10
    }
    //@discardableResult 可以消除调用的时候无返回值的警告
    @discardableResult mutating func text1() -> Int{
        a += 1
        return a
    }
}
var car = Car()
car.text1()

subscript 下标

struct Car {
    var a = 0.0
    var b = 0.0
    // 返回值(Double) 确定了 newValue 和  get 返回值的类型
    subscript(index: Int) -> Double{
        set {
            if index == 0 {
                a = newValue
            }else if index == 1{
                b = newValue
            }
        }
        get{
            if index == 0 {
                return a
            }else if index == 1{
                return b
            }
            return 0
        }
    }
}
var car = Car()
car[0] = 11.1
car[1] = 22.2
print(car[0])
print(car[1])

你可能感兴趣的:(swift 基础(一))