Swift3.0 - 初始化和释放

Swift3.0 - 真的很简单
Swift3.0 - 数据类型
Swift3.0 - Array
Swift3.0 - 字典
Swift3.0 - 可选值
Swift3.0 - 集合
Swift3.0 - 流控制
Swift3.0 - 对象和类
Swift3.0 - 属性
Swift3.0 - 函数和闭包
Swift3.0 - 初始化和释放
Swift3.0 - 协议protocol
Swift3.0 - 类和结构体的区别
Swift3.0 - 枚举
Swift3.0 - 扩展
Swift3.0 - 下标
Swift3.0 - 泛型
Swift3.0 - 异常错误
Swift3.0 - 断言
Swift3.0 - 自动引用计数(strong,weak,unowned)
Swift3.0 - 检测API
Swift3.0 - 对象的标识
Swift3.0 - 注释
Swift3.0 - 元类型
Swift3.0 - 空间命名
Swift3.0 - 对象判等
Swift3.0 - 探究Self的用途
Swift3.0 - 类簇
Swift3.0 - 动态调用对象(实例)方法
Swift3.0 - 文本输出
Swift3.0 - 黑魔法swizzle
Swift3.0 - 镜像
Swift3.0 - 遇到的坑

注意

1.系统要求存储属性必须初始化
2.可选值可以不用初始化,如果不初始化值,系统默认用nil初始化它
3.如果非可选类型存储属性不设置默认值,则必须在初始化方法中对其进行初始化
4.类必须自己写初始化方法,初始化没有默认值的非可选存储属性
5.结构体系统默认会添加初始化方法,当然自己也可以自定义
6.子类如果没有自己的初始化方法,系统默认使用父类的初始化方法,一旦有了自己的初始化方法,或者重写了父类的初始化方法,则父类的所有初始化不能被子类调用
7.你可以给子类添加和父类相同的初始化方法,但需要加上override 修饰
8.重写父类的convenience修饰的方便初始化方法,不需要加override 关键字

  • 指定初始化(Designated)

1.可以有多个指定初始化方法

class Person{
var name:String
var age:Int = 0
var weight:Double = 0.0
var height:Double = 0.0
init(name:String,height:Double) {
    self.name = name
    self.height = height
}
init(name:String) {
    self.name = name
}
}
  • 方便初始化(convenience)

记住:

1.在同一个类,使用convenience修饰的初始化方法必须调用一个其他初始化方法
2.convenience 必须最终调用一个指定的初始化方法
3.当子类继承父类时,子类的初始化方法,必须调用父类的指定初始化方法,不能调用使用convienience修饰的方便初始化方法
4.在swift3.0 初始化中,可以自己调用自己的初始化方法,系统不会检测出来,在创建convenience方便初始化方法的时候,需要小心,千万不要相互引用了

1594482-120578a2c07a954b.png
看图理解更透彻

实例代码

// 父类
class Person{
    var name:String
    var age:Int = 0
    var weight:Double = 0.0
    var height:Double = 0.0
    init(name:String,height:Double) {
        self.name = name
        self.height = height
    }
    init(name:String) {
        self.name = name
    }
    // 1.定义一个convenience 修饰的初始化方法,如果在同一个类中必须 调用其他没有convenience修饰的初始化方法
    convenience init(name:String,age:Int){
        self.init(name:name)
        self.age = age
    }
    // 2.如果定义两个或者多个convenience 修饰的初始化,只需要调用任意一个初始化方法即可满足语法要求
    convenience init(name:String,age:Int,weight:Double){
        self.init(name:name,age:age)
        self.weight = weight
    }
}
// 子类
class Man: Person {
    var address:String = ""
    init(name:String,age:Int,weight:Double) {
         // 3.必须调用父类指定初始化方法,不能调用convenience 修饰的方便初始化方法
         super.init(name: name)
    } 
}
1594482-edcacbc9905eb64c.png
看完代码这种图就好理解了
  • 类初始化的过程

第一阶段

1.调用指定初始化方法或者方便初始化
2.给新的实例分配内存,但内存还没有初始化
3.指定初始化方法确定所有存储属性都被初始化,内存这个时候被初始化
4.然后去调用父类的指定初始化方法,任务和调用自己指定初始化方法相同
5.继续在类继承链中指定上述过程,直到达到链的顶部为止
6.当到完成基类的初始化的时候,实例的初始化算是完成了,我们的第一阶段完成

第二阶段

1.可以对属性值进行修改
2.可以调用对象方法

  • 重写初始化方法

先看一个例子

// 父类
class Person{
    var name:String
    var age:Int = 0
    var weight:Double = 0.0
    var height:Double = 0.0
    init(name:String,height:Double) {
        self.name = name
        self.height = height
    }
    init(name:String) {
        self.name = name
    }
    convenience init(name:String,age:Int,weight:Double){
        self.init(name:name)
        self.age = age
        self.weight = weight
    }
}
 // 子类
  class Man: Person {
var address:String = ""

   // 重写父类指定初始化方法
    override init(name:String) {
        super.init(name: name)
    }
    // 重写父类convenience 修饰的初始化方法 不需要添加override 关键字
     init(name:String,age:Int,weight:Double){
        super.init(name: name)
    }
    // 创建自己的初始化方法
    convenience      init(name:String,age:Int,weight:Double,address:String){
        self.init(name: name)
        self.address = address
        self.age = age
        self.weight = weight
    }  
}

总结:

1.创建新的指定初始化方法,必须调用父类的指定初始化方法 (Designated)
2.创建新的方便初始化方法,必须调用自己的指定初始化方法,或者方便初始化方法(convenience)
3.重写父类的指定初始化方法,在方法名前加override ,然后调用父类的指定初始化方法
4.重写父类的方便初始化方法(convenience) 不需要加override 或者convenience 关键字,调用父类的指定初始化方法,如果加上convenice关键字,则必须调用自己的初始化方法
5.如果子类没有初始化方法,系统会自动继承父类的初始化方法
6.初始化调用父类初始化时,需要先初始化子类的存储属性,但是如果是convenience修饰的初始化方法,要先调用自己的其他初始化方法,然后再给自己的存储属性赋值

  • 创建一个可能失败的初始化方法

注意:

1.不能在重写的初始化方法改为可能失败的初始化方法
2.不能使用相同的参数定义一个可能失败的初始化方法和不会失败的初始化方法
3.可能失败的类型可以重写为不会失败类型
4.init? 可以被重写为init!,当然可逆也是可以的
5.init?和init! 都可以被重写为init

例子1

class Man: Person {
    var address:String = ""
    convenience  init?(name:String,age:Int,weight:Double,address:String){
    if name == "" {
        return nil
    }
    self.init(name: name)
    self.address = address
    self.age = age
    self.weight = weight
    }
}

例子2

enum TemperatureUnit {
    case kelvin, celsius, fahrenheit
    init?(symbol: Character) {
        switch symbol {
       case "K":
            self = .kelvin
        case "C":
            self = .celsius
        case "F":
            self = .fahrenheit
        default:
            return nil
        }
    }
}

例子2: 子类将父类可能失败的初始化方法,修改为不会失败的类型

class Animal{
    var name:String
    init?(name:String) {
        if name.isEmpty {
            return nil
        }
        self.name = name
    }
}

对于可能出现空值的对象或者其他类型,在使用之前必须进行验证

enum TemperatureUnit: Character {
case kelvin = "K", celsius = "C", fahrenheit = "F"
}

let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
    print("This is a defined temperature unit, so initialization     succeeded.")
}

需求: 创建一个文件类,文件名字可以为nil,但是不能为空即""

写法一:

class Document {
    var name:String?
    init?(name:String?){
        if name != nil && name!.isEmpty{
            return nil
        }
        self.name = name
    }
}

分析这种写法

只有一种初始化方法,也就是说,不管有没有名字,我们都需要给初始化传个参数,显然这样不合理,目标不明确

写法二:

class Document {
var name: String?
init() {} // 专门初始化name为 nil的情况 
init?(name: String) { // 传入名字 ,肯定不为nil ,只需要判断是否为空即可
    if name.isEmpty { return nil }
    self.name = name
}
}

疑问: init! 和init? 被重写为init 的意义何在?

暂时没想到

  • 需要的初始化方法(required)
    注意

1.子类必须重写父类用required修饰的方法
2.可以和convenience 组合使用

a-1.父类要求一个初始化方法被重写

class Person{
    var name:String
    var age:Int = 0
    var weight:Double = 0.0
    var height:Double = 0.0
    init(name:String,height:Double) {
        self.name = name
        self.height = height
    }
    init(name:String) {
        self.name = name
    }
   // 要求子类必须重写这个方法
   required convenience init(name:String,age:Int,weight:Double){
        self.init(name:name)
        self.age = age
        self.weight = weight
    }
}

a-2.子类重写父类要求的初始化方法

class Man: Person {
    var address:String = ""
    // 重写父类要求的初始化convenience 修饰的初始化方法 不需要添加override 关键字
    required init(name:String,age:Int,weight:Double){
    super.init(name: name)
   }
}
  • 反初始化(deinit)

注意:

1.deinit 在对象被释放前调用

写法很简单

deinit {
}

苹果文档有个例子简单讲解了一下它的重要性
例子: 有一个赌徒在银行存了10_000 元,赌徒从银行取钱然后去赌博,当赌徒对象释放了就将钱全部存到银行

class Bank {
    static var coinsInBank = 10_000
    static func distribute(coins numberOfCoinsRequested: Int) -> Int {
        let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
        coinsInBank -= numberOfCoinsToVend
        return numberOfCoinsToVend
    }
    static func receive(coins: Int) {
        coinsInBank += coins
    }
}

赌徒类

class Player {
    var coinsInPurse: Int
    init(coins: Int) {
        coinsInPurse = Bank.distribute(coins: coins)
  }
   func win(coins: Int) {
        coinsInPurse += Bank.distribute(coins: coins)
   }
  deinit {
        Bank.receive(coins: coinsInPurse)
    }
}

执行

var playerOne: Player? = Player(coins: 100)
playerOne!.win(coins: 2_000)
playerOne = nil
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值