Swiftyjson: Memory leak in XCode 7.1 beta

Created on 10 Sep 2015  路  16Comments  路  Source: SwiftyJSON/SwiftyJSON

I use Alamofire to make an API call and use SwiftyJSON to wrap around the json response. XCode Instrument shows that there's memory leak created by Alamofire library.
Here's the code (pretty simple) :

Alamofire.request(service.method, service.url, parameters: nil, encoding: ParameterEncoding.URL,
headers: headers).responseJSON(completionHandler: { (req, res, result) -> Void in

       // This line leak the memory
       let json = JSON(result.value!)
    })

If i comment out the line let json = JSON(result.value!) then no more memory leak.

bug

Most helpful comment

There is only one block of code that has the switch... as expressions. I modified the following code in the SwiftyJSON.swift file and the memory leak went away:

if let number = newValue as? NSNumber {
if number.isBool {
_type = .Bool
} else {
_type = .Number
}
self.rawNumber = number
} else if let string = newValue as? String {
_type = .String
self.rawString = string
} else if let _ = newValue as? NSNull {
_type = .Null
} else if let array = newValue as? [AnyObject] {
_type = .Array
self.rawArray = array
} else if let dictionary = newValue as? [String : AnyObject] {
_type = .Dictionary
self.rawDictionary = dictionary
} else {
_type = .Unknown
_error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
}

                    /*
        switch newValue {
        case let number as NSNumber:
            if number.isBool {
                _type = .Bool
            } else {
                _type = .Number
            }
            self.rawNumber = number
        case  let string as String:
            _type = .String
            self.rawString = string
        case  _ as NSNull:
            _type = .Null
        case let array as [AnyObject]:
            _type = .Array
            self.rawArray = array
        case let dictionary as [String : AnyObject]:
            _type = .Dictionary
            self.rawDictionary = dictionary
        default:
            _type = .Unknown
            _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
        }
        */

So this is the right workaround.
screenshot 2015-09-18 19 28 58

All 16 comments

Is this with master or the xcode7 branch?

Hi,

It seems that XCode apps are quite unreliable now. I tried with XCode 7.1 beta then it shows memory leak. I tried with XCode 7.0 GM then no memory leak. I highly believe this is XCode problem, because i did investigate this issue and it seems that SwiftyJSON doesn't do anything that can cause the memory leak.
I'll keep monitoring it more.

I have detected the same memory leak problem with the JSON(result) with xCode 7.0 GM. I commented out the let json = JSON(result) line and the leak went way. Am I using the code incorrectly? I have a lot of Alamofile URL Get and JSON results, this caused my application to run out of memory quickly.

Could this be the same memory leaks in the Argo swift? See https://github.com/thoughtbot/Argo/issues/205. This is related to Switch ... as.. statement that Apple said that could result in memory leak.

According to Apple xCode 7.0 release note.

https://developer.apple.com/library/prerelease/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc7_release_notes.html


Using switch against multiple types with as patterns may cause a memory leak. For example, avoid this kind of switch statement:
switch x {
case let a as A: ...
case let b as B: ...
case let c as C: ...
default: ...
}

Rewrite the code to use if let a = x as? A statements instead of switch. This pattern performs type checks that avoid the memory leak. (22587077)

SwiftyJSON uses the syntax extensively. We need a workaround ASAP.

There is only one block of code that has the switch... as expressions. I modified the following code in the SwiftyJSON.swift file and the memory leak went away:

if let number = newValue as? NSNumber {
if number.isBool {
_type = .Bool
} else {
_type = .Number
}
self.rawNumber = number
} else if let string = newValue as? String {
_type = .String
self.rawString = string
} else if let _ = newValue as? NSNull {
_type = .Null
} else if let array = newValue as? [AnyObject] {
_type = .Array
self.rawArray = array
} else if let dictionary = newValue as? [String : AnyObject] {
_type = .Dictionary
self.rawDictionary = dictionary
} else {
_type = .Unknown
_error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
}

                    /*
        switch newValue {
        case let number as NSNumber:
            if number.isBool {
                _type = .Bool
            } else {
                _type = .Number
            }
            self.rawNumber = number
        case  let string as String:
            _type = .String
            self.rawString = string
        case  _ as NSNull:
            _type = .Null
        case let array as [AnyObject]:
            _type = .Array
            self.rawArray = array
        case let dictionary as [String : AnyObject]:
            _type = .Dictionary
            self.rawDictionary = dictionary
        default:
            _type = .Unknown
            _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
        }
        */

So this is the right workaround.
screenshot 2015-09-18 19 28 58

I just found out exactly the same as Tehong. It seems that this is bug with Swift, but has been fixed in XCode 7.1 beta 2.

Has this been addressed yet? I am seeing this too in XCode 7.0

This is addressed in XCode 7.1 beta 2. It is in the release notes.

Is there a pr with a workaround that those of us not using Xcode 7.1 beta 2 can use?

I don't think so. Just modify SwiftyJSON.swift in your xCode SwiftyJSON framework directory as I did and that will eliminate the memory leak for any product produced with xCode prior to xCode 7.1 beta 2.

I just ran into this on Xcode 7.0.1 and can confirm @tehong's solution works.

:+1:

@tehong That worked for me too. Thanks

+1

This issue has been inactive for a while so I'm gonna go ahead and consider it fixed. Please let us know if you want to reopen it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ejpusa picture ejpusa  路  5Comments

otaran picture otaran  路  7Comments

dubiao picture dubiao  路  6Comments

MrLoveQD picture MrLoveQD  路  5Comments

amit-bhavsar picture amit-bhavsar  路  5Comments