Swift 内存管理是如何工作的? [英] How does Swift memory management work?

查看:41
本文介绍了Swift 内存管理是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具体来说,Swift 内存管理如何使用委托模式与可选项一起工作?

Specifically, how does Swift memory management work with optionals using the delegate pattern?

习惯于在Objective-C中编写委托模式,我的直觉是让委托weak.例如,在 Objective-C 中:

Being accustomed to writing the delegate pattern in Objective-C, my instinct is to make the delegate weak. For example, in Objective-C:

@property (weak) id<FooDelegate> delegate;

但是,在 Swift 中执行此操作并不是那么简单.

However, doing this in Swift isn't so straight-forward.

如果我们只是一个普通的协议:

If we have just a normal looking protocol:

protocol FooDelegate {
    func doStuff()
}

我们不能将这种类型的变量声明为弱变量:

We cannot declare variables of this type as weak:

weak var delegate: FooDelegate?

产生错误:

'weak' 不能应用于非类类型 'FooDelegate'

'weak' cannot be applied to non-class type 'FooDelegate'

所以我们要么不使用关键字weak,它允许我们使用structsenums作为委托,或者我们改变我们的协议如下:

So we either don't use the keyword weak, which allows us to use structs and enums as delegates, or we change our protocol to the following:

protocol FooDelegate: class {
    func doStuff()
}

允许我们使用weak,但不允许我们使用structsenums.

Which allows us to use weak, but does not allow us to use structs or enums.

如果我不让我的协议成为类协议,因此不使用 weak 作为我的变量,我正在创建一个保留循环,对吗?

If I don't make my protocol a class protocol, and therefore do not use weak for my variable, I'm creating a retain cycle, correct?

有什么可以想象的理由为什么任何打算用作委托协议的协议不应该是类协议,以便这种类型的变量可以weak?

Is there any imaginable reason why any protocol intended to be used as a delegate protocol shouldn't be a class protocol so that variables of this type can be weak?

我主要是问,因为在关于 Swift 协议的 Apple 官方文档,他们提供了一个非类协议和一个非弱变量的示例,用作其类的委托:

I primarily ask, because in the delegation section of the Apple official documentation on Swift protocols, they provide an example of a non-class protocol and a non-weak variable used as the delegate to their class:

protocol DiceGameDelegate {
    func gameDidStart(game: DiceGame)
    func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
    func gameDidEnd(game: DiceGame)
}

class SnakesAndLadders: DiceGame {
    let finalSquare = 25
    let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
    var square = 0
    var board: [Int]
    init() {
        board = [Int](count: finalSquare + 1, repeatedValue: 0)
        board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
        board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
    }
    var delegate: DiceGameDelegate?
    func play() {
        square = 0
        delegate?.gameDidStart(self)
        gameLoop: while square != finalSquare {
            let diceRoll = dice.roll()
            delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
            switch square + diceRoll {
            case finalSquare:
                break gameLoop
            case let newSquare where newSquare > finalSquare:
                continue gameLoop
            default:
                square += diceRoll
                square += board[square]
            }
        }
        delegate?.gameDidEnd(self)
    }
}

我们是否应该将此视为 Apple 认为我们应该使用结构体作为委托的暗示?或者这只是一个不好的例子,实际上,委托协议应该声明为仅类协议,以便委托对象可以持有对其委托的弱引用?

Should we take this as a hint that Apple thinks we should be using structs as delegates? Or is this simply a bad example, and realistically, delegate protocols should be declared as class-only protocols so that the delegated object can hold a weak reference to its delegate?

推荐答案

我们是否应该将此视为 Apple 认为我们应该使用结构体作为委托的暗示?或者这只是一个不好的例子,实际上,委托协议应该声明为仅类协议,以便委托对象可以持有对其委托的弱引用?

Should we take this as a hint that Apple thinks we should be using structs as delegates? Or is this simply a bad example, and realistically, delegate protocols should be declared as class-only protocols so that the delegated object can hold a weak reference to its delegate?

事情就是这样.在现实生活中的 Cocoa 编程中,委托很可能是一个现有的类.它是一个类,因为它存在于只有一个类才能满足的其他目的 - 因为 Cocoa 需要它.

Here's the thing. In real life Cocoa programming, the delegate is likely to be an existing class. It is a class because it exists for some other purpose that only a class can satisfy - because Cocoa demands it.

例如,很多时候,以 iOS 为例,一个视图控制器需要充当另一个视图控制器的委托,以便在它们之间来回安排消息.视图控制器的所有权由视图控制器层次结构决定,没有别的.所以,在 Swift 中,就像在 Objective-C 中一样,你更好delegate 属性 weak,因为如果一个视图会很糟糕控制器突然获得了另一个视图控制器的内存管理所有权!

For example, very often, to take iOS as an example, one view controller needs to act as another view controller's delegate for purposes of arranging a message back and forth between them. Ownership of the view controllers is dictated by the view controller hierarchy and by nothing else. So, in Swift, just as in Objective-C, you had better make that delegate property weak, because it would be terrible if one view controller suddenly took memory management ownership of another view controller!

因此,在 Cocoa 框架的现实世界中,存在不正确的所有权或保留周期的严重危险.这就是 weak 解决的问题.但正如您所说,它只适用于类.

So, in the real world of the Cocoa framework, there is serious danger of incorrect ownership or of a retain cycle. And that is the problem that weak solves. But it only works, as you rightly say, with classes.

然而,书中的例子是关于一些对象生活在一个抽象的人造人造 Swift 世界中.在那个世界中,只要您没有循环(保留循环)的危险,就没有理由不使用结构,也没有理由担心内存管理.但那个世界不是你通常会在其中编程的世界!而那个世界并不是你的 Objective-C 委托模式来自并属于的框架 Cocoa 世界.

The example in the book, however, is about some objects living off in an abstract made-up artificial Swift-only world. In that world, as long as you aren't in danger of circularity (retain cycle), there's no reason not to use structs and there's no reason to worry about memory management. But that world is not the world you will usually be programming in! And that world is not the framework Cocoa world that your Objective-C delegate pattern comes from and belongs to.

这篇关于Swift 内存管理是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆