Swift基础:1.浅识类和结构体(上)

149 阅读5分钟

Everrthing is an Object? In swift, "everything is an object." That's a boast common to various modern object-oriented languages, but what does it mean? In Swift object type are declared with the flavor of the object type(enum, struct or class). 进入正题,class是引用类型,定义如下: 一.类定义

class Swifter: NSObject {
// 声明存储属性
let id = "Swift"
var name:String
var age:Int
var bodyWeight: Float
var foodWeight: Float?

// 构造器 指定构造器 required修饰构造器 可失败的构造器 以及遍历构造器
init(_ name:String, setAge age: Int, body bodyWeight: Float) {

     self.name = name
     self.age = age
     self.bodyWeight = bodyWeight
     super.init()
      }
      
// required修饰的构造器 注意 不是required修饰的构造器就一定要实现
/**
如果子类不指定任何自己的构造器,直接继承父类的构造器时,不必再实现父类required修饰的构造器
如果子类实现了自己的构造器(或者显示override父类的某个指定构造器),就必须实现重写required修饰的构造器
*/
required init(name: String, age:Int, bodyWeight: Float) {
      self.name = name
      self.age = age
      self.bodyWeight = bodyWeight
      super.init()
     }
    
 // 可失败的构造器
 /**
 实际上就是提供一个返回nil的条件让构造器初始化失败
 */
 init?(_ name:String,setAgeOrInvalid age:Int, body bodyWeight: Float) {
     if age < 0 || age> 150 { // age < 0 , age > 150 <=> age <0 && age > 150
     return nil
     }
     self.name = name
     self.age =age
     self.bodyWeight = bodyWeight
 }
 
 // 便利构造器
 /**
  关键字 convenience
  Convenience initializer
  A convenience initializer is marked with the keyword convenience.
  It is a delegating intializer; it must contain the phrase self.init(...).
  Moreover, a convience initializer must ultimately delegate to a designated initializer:
  when it says self.init(...), it must call a designated initializer in the same class -- 
  or, if it calls another convenience initializer in the same calss, the chain of convenience 
  initializers must end by calling a designated initializer in the same class.
  简单总结就是便利构造器最终会调用指定构造器,可以用来封装底层构造器收缩参数列表
 */
 
 convenience init(_ name: String) {
   self.init(name: name, age: 11, body: 10)
 }
 
 // 可失败的便利构造器
 convenience init?(theName name: String)
    let localName = name as NSString
    if localName.length == 0 {
    return nil 
    }
    
    self.init(name,setAge: 10, body: 11 )
}

// 析构器 
/**
 析构器:与它成对应关系的就是构造器,析构用来在对象释放的时候提供一个操作的时机
*/

// 对象函数,类函数,静态函数不是当前讨论重点省略

总结:

1.一个class类中可以由属性(存储/静态也可以使用lazy或者static修饰)、构造器(便利构造器、指定构造器、)、函数(类函数、对象函数、静态函数、下标函数)、析构器组成。

构造器的规则: 如果子类有自己指定的构造器,就必须实现父类required修饰的指定构造器; 如果子类没有自己的构造器,就直接继承父类的构造器不用重写父类required 修饰的构造器。 便利构造器: keyWord关键字convenience,本质上便利构造器调用某个指定构造器,便利构造器的优点是压缩参数列表。

析构器:与构造器对应,释放对象的时候调用

2.存在继承关系

3.修改属性的函数不用mutating关键字修饰

4.存放在堆区

二.类的生命周期 iOS开发的语言不管是OC还是Swift后端都是通过LLVM进行编译的,如下图所示:

LLVM编译行为.png

OC通过clang编译器编译成IR,然后再生成可执行文件.o(机器码)。 Swift通过Swift编译器编译成IR然后生成可执行文件。

添加target增加脚本如图:

swift脚本.png 生成一个ViewController.sil文件,摘抄部分主要内容

class Swifter {
  @_hasStorage @_hasInitialValue final let id: String { get }
  @_hasStorage var name: String { get set }
  @_hasStorage var age: Int { get set }
  @_hasStorage @_hasInitialValue var bodyWeight: Float? { get set }
  @_hasStorage @_hasInitialValue var data: Data? { get set }
  init(_ name: String, setAge age: Int)
  required init(name: String, age: Int)
  init?(_ name: String, setAgeOrInvalid age: Int)
  convenience init(_ name: String)
  convenience init?(theName name: String)
  func objFunction()
  class func clsFunction()
  final func doNotPermissionOverride()
  static func staticFunction()
  @objc deinit
}

对应上面Swifter类的声明逐行解读: 首先存储属性,let定义的属性变量解析出来实际上就是get属性;var定义的属性变量解析出来就是get-set属性。指定构造器、便利构造器以及可失败的构造器与Swift雷同。定义的对象方法、类方法也容易识别。稍微注意一点的就是析构器使用了@objc修饰,这个修饰词的作用就是:

1.当Swift需要使用OC的语言特性时,例如当需要声明协议中的可选方法和可选属性时。

2.当需要发送潜在的消息给AnyObject对象的时候可以使用(该对象没有@objc修饰的属性或者函数,可以在一定程度上不抛出异常)。举例:

@objc发送消息到AnyObject.png

3.当Swift需要暴露给OC代码时使用@objc标记。例如将Swift的enum暴露给Objective-C使用。关于@objc的其他操作会择日进行全部阐述。

二.结构体

struct Swifter {
let id = "Swift"
var name:String
var age:Int
var bodyWeight: Float
var foodWeight: Float?

// 1.构造器隐式实现
//init(...){
// 构造器自动生成
//}

// 导致结构体对象重新创建添加mutating关键字修饰
mutating func changeProtperty(newAge new:Int)-> Void {
  self.age = new
}

//下标函数(class类型同理)
// 下标函数 在非枚举类型使用的时候 可以用来获取成员属性的某个部分
   subscript(index: Int)-> String {

       get {
          let str = self.id
          return index < (str as NSString).length && index >= 0 ? String(str[str.index(s.startIndex,offsetBy: Index)]) : String("越界")
       }   
   }
}
// 调用下标函数 引用类型不再赘述
let swifter: Swifter = Swifter.init(name: "Nicole",age: 12, weight: 10, foodWeight: 2)
let str = swifter[0] // “S”

总结:

1.结构体构造器可以隐式实现(和class的主要区别)

2.不存在继承关系(和class的主要区别)

3.成员属性被修改时(值类型属性更改以及引用类型属性地址改变)会重新创建新的结构体对象

4.函数更改成员导致需要重新创建结构体对象时,该函数使用mutating修饰

5.存放在栈区