Learn Swift - Section 3rd 类与结构体

类与结构体的共同点:

  • 定义属性用于存储值
  • 定义方法用于提供功能
  • 定义附属脚本用于访问值
  • 定义构造器用于生成初始化值
  • 通过扩展以增加默认实现的功能
  • 实现协议以提供某种标准功能

与结构体相比,类还有如下的附加功能:

  • 继承允许一个类继承另一个类的特征
  • 类型转换允许在运行时检查和解释一个类实例的类型
  • 解构器允许一个类实例释放任何其所被分配的资源
  • 引用计数允许对一个类的多次引用

更多信息请参见继承,类型转换,析构过程,和自动引用计数。

注意

  • 结构体总是通过被复制的方式在代码中传递,不使用引用计数。

<h3 id = "1">1.值类型与引用类型</h3>
值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝。

在之前的章节中,我们已经大量使用了值类型。实际上,在 Swift 中,所有的基本类型:整数(Integer)、浮点数(floating-point)、布尔值(Boolean)、字符串(string)、数组(array)和字典(dictionary),都是值类型,并且在底层都是以结构体的形式所实现。

在 Swift 中,所有的结构体和枚举类型都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。

“与值类型不同,引用类型在被赋予到一个变量、常量或者被传递到一个函数时,其值不会被拷贝。因此,引用的是已存在的实例本身而不是其拷贝。”

var marray = ["lopl","liu","han"]
func modifyArray()  {
    var saray = marray
    saray.removeAtIndex(2)
}
modifyArray()
marray//并没有变,说明是值拷贝

<h3 id = "2">2.将结构体实例赋值给一个常量,则无法修改结构体中的属性,即使属性是变量。</h3>

struct Cars {
    var name = ""

}
let car = Cars()
car.name = "Audi"
//而类则可以修改,因为类是引用类型。
class CreateNewLife{
    var name = ""
}
class Animals {
    var kind = ""
    let planet = "Earth"
    lazy var createNewLife = CreateNewLife()
}
let life = CreateNewLife()
let anAnimal = Animals()
anAnimal.kind = "Human"
print(anAnimal,life)
if life === anAnimal {
    print("same class")
}else{
    print("Different class")
}
print(anAnimal.createNewLife.name)//这时CreateNewLife实例才会被创建
anAnimal.createNewLife.name = "liven"
print(anAnimal.kind,anAnimal.createNewLife.name)

<h3 id = "3">3.结构体和类中的属性定义-getter和setter</h3>

struct Point{
    var x = 0.0,y = 0.0
}
struct Size {
    var width = 0.0,height = 0.0
}
struct Rect {
    var origin = Point()
    var size   = Size()
    var center:Point{//计算属性:即写了get或set的属性。如果只有get,就是只读属性
        get{
            let centerX = origin.x + size.width/2
            let centerY = origin.y + size.height/2
            return Point(x: centerX, y: centerY)
        }
        set(newCenter){
            origin.x = newCenter.x - size.width/2
            origin.y = newCenter.y - size.height/2
        }
    }
    var arcPoint:Point{//属性观察器didSet,willSet
        willSet(newValue){//会将新的值传入
            print("will set arcPoint \(newValue)")
        }
        didSet(oldValue){//会将旧的值传入
            //arcPoint = Point(x: 8, y: 9)
            print("did set arcPoint \(arcPoint) \(oldValue)")
        }
    }
    static var name = "my rect"//Type property类型属性

    //值类型属性一般不能在它自己的实例方法中修改;如果非要修改,需要加关键字mutating
    mutating func bigger(x:Double,y:Double) {
        size.width  += x
        size.height += y
    }
}

Rect.name
Rect.name = "xxxx"
Rect.name

var rect = Rect(origin: Point(x: 10,y: 10), size: Size(width: 20,height: 30), arcPoint: Point(x: 1, y: 1))
print(rect.arcPoint)
rect.arcPoint = Point(x: 3, y: 4)
print(rect.arcPoint)

var rect2 = rect
rect2.arcPoint = Point(x: 6, y: 6)
print(rect.arcPoint,rect2.arcPoint)

rect.bigger(20, y: 20)
print(rect.size)
class SomeClass {
    class var overrideProperty:Int{//get省略了。class关键字表示重写父类的getter实现
        return 10
    }
}

<h3 id = "4">4.方法</h3>

struct LevelTraker {
    static var highestUnlockedLevel = 1
    static func unlockLevel(level:Int){
        if (level == highestUnlockedLevel + 1) {highestUnlockedLevel = level}
    }
    static func levelIsUnlocked(level:Int)->Bool{
        return level <= highestUnlockedLevel
    }
    var currentLevel = 1
    mutating func advanceLevel(level:Int)->Bool{
        if LevelTraker.levelIsUnlocked(level) {
            currentLevel = level
            return true
        }else{
            return false
        }
    }
}

class Player {
    var traker = LevelTraker()
    var playerName:String
    func completeLevel(level:Int) ->Bool{
        LevelTraker.unlockLevel(level+1)
        if traker.advanceLevel(level+1){

            return true
        }else{
            print("Level \(level) hasn't been unlocked")
            return false
        }
    }
    init(name:String){
        playerName = name
    }
}
var level111 = LevelTraker()
var level121 = LevelTraker()
level121.currentLevel = 2
print(level111.currentLevel, level121.currentLevel)

var player = Player(name:"han")
player.traker.currentLevel
player.completeLevel(1)
player.traker.currentLevel
LevelTraker.highestUnlockedLevel
player.completeLevel(5)

<h3 id = "5">5.构造过程</h3>

class Cars{
    var brand:String
    var usage:String
    //构造函数
    init(){
        brand = "BMW"
        usage = "Family"
    }
    init(_brand:String,_usage:String){
        brand = _brand
        usage = _usage
    }
}

let audi = Cars(_brand: "Audi", _usage: "Sports")
print(audi.brand,audi.usage)
let car2 = Cars()
print(car2.brand,car2.usage)

<h3 id = "6">6.当属性有默认值,且没有构造方法时,结构体和类拥有默认构造方法。但是结构体可以有带属性参数的默认构造方法(逐一成员构造器),而类没有。</h3>

struct People {
    var name:String?
    var sex:String?
}
class Books {
    var type:String?
    var category:String?
    var available = true
}
let p = People()
let semdsd = People(name: "han", sex: "famale")
let book   = Books()
//var book2  = Books(type:"epub",category:"Computer",available:true)

<h3 id = "7">7.析构过程</h3>
/**

  • 析构器只适用于类类型,不能用于结构体。析构器用deinit关键字。
    */
class Telephones {
    var type:String?
    var category:String?
    var available = true

    init() {
        //
    }
    deinit{
        //析构代码。。。
        print("\(type)")
        available = false
    }
}

/*
析构过程会在ARC回收实例时被系统调用,不需要手动调用。
*/

<h3 id = "8">8.类实例之间的循环强引用</h3>
解决方式:
1.使用weak关键字,弱引用
2.使用unowned,无主引用

<h3 id = "9">9.解决闭包引起的循环引用--定义捕获列表</h3>

protocol SellProducts{
    func sellProducts(product:String)
}

class Person {
    var name:String
    weak var delegate:Seller?
    lazy var someClosure:(Int,String)->String = {
        //在闭包中将self修饰为无主引用。将delegate 修饰为 弱引用
        [unowned self,weak delegate = self.delegate!]//捕获列表
        (index:Int,strToProcess:String)->String in

        return "\(self.name),\(self.delegate),\(delegate)"
    }
    init(name:String,delegate:Seller?){
        self.name = name;
        self.delegate = delegate;
    }

    func giveSellerProducts(product:String ) -> Bool {

        self.delegate?.sellProducts(product)
        return true
    }
}

class Seller : SellProducts{
    var product:String?
    func sellProducts( product: String) {
        self.product = product
    }
}
let seller = Seller()
var person = Person (name: "Hanliu", delegate: seller)


//刚开始seller是没有商品的,要等到Person给seller
print(seller.product)
//person告诉seller,帮我卖苹果
person.giveSellerProducts("apple")
//现在seller手中就有了商品了
print(seller.product!)

person.someClosure(1,"haha")
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容