Leaks in Swift 3/iOS 10

Leaks in Swift 3 / iOS 10

I had the same problem and spent a lot of time digging. I found that if you create a Swift object from Objective-C code and the Swift object has a native Swift dictionary property, you will see this leak. It won't happen if all the code is Swift, and more usefully, it won't leak if you change the native Swift dictionary to an NSDictionary. This also applies to Swift Set's and NSSet's. I also saw that the leak happens on iOS 10 and not on iOS 9.

// LeakySwiftObject.swift
class LeakySwiftObject: NSObject {
let dict = [String: String]() // <- Any native Swift dictionary will reproduce the leak
}

// ObjectiveCObject.h
@class LeakySwiftObject;

@interface ObjectiveCObject : NSObject
@property (strong) LeakySwiftObject *leaky;
@end

// ObjectiveCObject.m
@implementation ObjectiveCObject

- (instancetype)init
{
self = [super init];
if (self) {
self.leaky = [LeakySwiftObject new];
}
return self;
}

@end

// ViewController.swift
class ViewController: UIViewController {
let testObj = ObjectiveCObject()
}

The Leaks Instrument reports a leak:

_NativeDictionaryStorageImpl<String,String>

_NativeDictionaryStorageOwner<String,String>

Swift 3 & iOS 10 false memory leak bug

I've tried different variations to confirm it's indeed a bug and my findings are:

  1. When you don't assign c in the sample code to someProperty, both instances will print the string in their respective deinits. A true strong reference cycle won't deinit.
  2. When SomeClass doesn't inherit from NSObject, this bug doesn't happen.
  3. When using Swift 2.2, this doesn't happen.
  4. When using iOS 9-, this doesn't happen.
  5. Once someProperty is set to nil somewhere in the code, both instances are deinited. Xcode 8 memory debugger confirms there are no memory leaks. However in Instruments, this change isn't reflected--rightfully so, since a real memory leak probably won't be resolved.

FYI, this doesn't happen only when it's assigned to a property of UIViewController. I originally found out about this behavior in a singleton object.

Swift 3 enums leak memory when the class contains an array

Hey @endavid managed to replicate the issue consistently. We spend a good time trying to figure out what was going on and your post helped a lot!

Here is the sample repo: https://github.com/Giphy/ios-memory-leak-sample

Radar: https://openradar.appspot.com/radar?id=4992108083544064

We are developing SDKs and same exact issue surfaced with a small difference. Since we wanted things to interop we added @objc to the enum definition and things started to leak exactly the way you described given your class has two properties, one enum and one mutable array.

Consistently reproduced the leak:

// Without @objc this enum won't leak
// however when this enum is included in a class
// which contains an array, it will leak
@objc enum leakingObjCMarkedEnum: Int {

// Just some random cases.
case apple, orange
}

// Wrapper class which contains an enum and Array
// The class needs to contain the the Array in order for
// the Enum to leak.
class WrapperClass {

// Optional enums marked with @objc will leak.
var leakyOptionalEnum: leakingObjCMarkedEnum?

// Include an array to trigger this behaviour.
// Empty arrays won't cause the leak, so lets add an arbitrary Int
var myArray: [Int] = [80]
}

class ViewController: UIViewController {

// Hang on to a reference to our Wrapper Class instance.
var wc: WrapperClass?

override func viewDidLoad() {
super.viewDidLoad()

// Allocate an instance of our class
// and things will start leaking at this point.
wc = WrapperClass()
}
}

Work Around:

If we convert the optional enum class property to a non-optional, leak will disappear.

// Let's convert the optional property to a non-optional
var leakyOptionalEnum: leakingObjCMarkedEnum = .orange

Edit:

It is fixed by guys @ Apple:
https://bugs.swift.org/browse/SR-5625
PR: https://github.com/apple/swift/pull/11341

MKMapView Instruments Memory Leak in iOS10

This was a bug and had been reported to Apple. It appears to have been corrected in iOS 11.

iOS10: How to avoid memory leaks in a segue circle


Presenting/Dismissing

NOTE:

If you are working with a navigation controller, you might want to check my answer about Pushing/Popping.


The action of "Back To Page1" in the fourth View Controller-, should be similar to:

@IBAction func backToPage01Tapped(_ sender: Any) {
presentingViewController?.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
}

Note that the reason of why the number of presentingViewController are three, because it's the number of previous View Controllers for the fourth one.

If you have only two previous View Controllers, then you must chain backwards twice and call dismiss from two View Controllers back:

presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)

and so on...

Xcode 10.2 detects memory leaks in a new single view app

The question is solved with the new Xcode 10.3 release!

Resolved an issue where running an app in iOS 12.2 or later under the
Leaks instrument resulted in random numbers of false-positive leaks
for every leak check after the first one in a given run. (48549361)



Related Topics



Leave a reply



Submit