无法解释的内存泄漏 swift iOS

Posted

技术标签:

【中文标题】无法解释的内存泄漏 swift iOS【英文标题】:Unexplainable memory leak swift iOS 【发布时间】:2014-11-24 12:43:46 【问题描述】:

我有一个超级简单的基本应用程序,

只有 1 个带有 collectionView 的视图控制器

我的collectionViewFlowLayout 泄漏了,我不知道为什么

Leaked Object   #   Address Size    Responsible Library Responsible Frame
__NSDictionaryM 1   0x7fcc4ca31340  48 Bytes    UIKit   UICollectionViewLayoutCommonInit
__NSDictionaryM 1   0x7fcc4ca313a0  48 Bytes    UIKit   UICollectionViewLayoutCommonInit
__NSDictionaryI 1   0x7fcc4ca31570  64 Bytes    UIKit   UICollectionViewFlowLayoutCommonInit
__NSDictionaryM 1   0x7fcc4ca313d0  48 Bytes    UIKit   UICollectionViewLayoutCommonInit
UICollectionViewFlowLayout  1   0x7fcc4ca310c0  512 Bytes   leak-application    ObjectiveC.UICollectionViewFlowLayout.__allocating_init (ObjectiveC.UICollectionViewFlowLayout.Type)() -> ObjectiveC.UICollectionViewFlowLayout
__NSDictionaryM 1   0x7fcc4ca31370  48 Bytes    UIKit   UICollectionViewLayoutCommonInit
__NSDictionaryM 1   0x7fcc4ca31400  48 Bytes    UIKit   UICollectionViewLayoutCommonInit
NSMutableIndexSet   1   0x7fcc4ca314e0  48 Bytes    UIKit   UICollectionViewLayoutCommonInit
NSMutableIndexSet   1   0x7fcc4ca31470  48 Bytes    UIKit   UICollectionViewLayoutCommonInit
__NSDictionaryM 1   0x7fcc4ca2f290  48 Bytes    UIKit   UICollectionViewLayoutCommonInit

这是我的代码

class ParallaxCollectionViewCell: UICollectionViewCell 

    let titleLabel = UILabel(frame: CGRectMake(0, 0, 100, 100))

    override init(frame: CGRect) 
        super.init(frame: frame)
        self.contentView.addSubview(titleLabel)
    

    required init(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
    



class ViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource 

    var collectionView: UICollectionView?
    let collectionViewLayout = UICollectionViewFlowLayout()

    override func viewDidLoad() 
        super.viewDidLoad()
        setup()
    

    func setup() 

        self.collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: self.collectionViewLayout)
        self.view.addSubview(self.collectionView!)

        self.collectionView?.delegate = self;
        self.collectionView?.dataSource = self;
        self.collectionView?.backgroundColor = UIColor.whiteColor()
        self.collectionView?.registerClass(ParallaxCollectionViewCell.self, forCellWithReuseIdentifier: "identfifier")

        self.collectionView?.reloadData()
    

    override func viewDidLayoutSubviews() 
        self.collectionView?.frame = self.view.bounds
    

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize 
        return CGSizeMake(CGRectGetWidth(self.view.bounds), 100)
    

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell 
        let parallaxCell = collectionView.dequeueReusableCellWithReuseIdentifier("identfifier", forIndexPath: indexPath)  as ParallaxCollectionViewCell
        parallaxCell.titleLabel.text = "test"
        return parallaxCell
    

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return 10
    

如果我将 collectionViewLayout 属性设为可选变量并在设置中分配它

var collectionViewLayout : UICollectionViewFlowLayout?
func setup() 
    self.collectionViewLayout = UICollectionViewFlowLayout()
    self.collectionView = UICollectionView(frame: CGRectZero, collectionViewLayout: self.collectionViewLayout!)
    ...

它不会泄漏..但这不是解决方案吗?

【问题讨论】:

【参考方案1】:

我之前遇到过一个与 NIB 加载相关的 Swift 错误,它可能导致属性被初始化两次。如果我没记错的话,在某些情况下,可以在同一个对象实例上调用两个不同的指定初始化程序,导致对象的实例属性被初始化两次,并且在第一次初始化期间实例化了任何东西。 (那是在 Cocoa 应用程序中使用 NSWindowController 的早期 Swift 测试版。我不知道当前 Swift 版本中是否仍然存在该错误。)

这可以解释您在 collectionViewLayout 属性中看到的泄漏,以及为什么在分配 setup() 中的属性时它没有泄漏。

您可以使用 Instruments 查看创建了多少 UICollectionViewFlowLayout 实例,或者您可以在 -[UICollectionViewFlowLayout init] 中设置一个符号断点,以查看它是否在您的 ViewController 初始化期间被调用了两次。

否则,它可能只是检漏仪中的误报。

要解决此问题,您可以尝试覆盖 init(coder:) 并在该方法中初始化您的 collectionViewLayout 属性:

required init(coder aDecoder: NSCoder) 
    self.collectionViewLayout = UICollectionViewFlowLayout()
    super.init(coder:aDecoder)

但是,您需要确认此初始化程序没有被调用两次。

【讨论】:

是的,我的断点似乎是 init 方法的两倍,有什么建议可以解决这个问题吗? 好像是这样的:***.com/a/26310782/62009 帮了我一把,谢谢你指出了双重初始化的方向。【参考方案2】:

由于CollectionView 具有delegatedatasource,您应该将其声明为weak 以避免保留周期(泄漏)。

【讨论】:

以上是关于无法解释的内存泄漏 swift iOS的主要内容,如果未能解决你的问题,请参考以下文章

内存泄漏,在do-catch块中。 iOS,Swift

从 NSObject 派生时,Swift iOS 内存泄漏指示 XCode8

将文本分配给UILabel(iOS,Swift 4,Xcode 9)时内存泄漏

解释 DrMemory 日志,内存泄漏 [关闭]

iOS - 无法消除内存泄漏

Swift 表格视图,在表格视图单元格中播放视频,内存泄漏