2015-10-08 136 views
1

我使用SwiftyJSON 2.3.0的JSON解析在我的雨燕2.0的項目:調試NSJSONSerialization內存泄漏

extension NSData { 
    func JSONDict() -> Dictionary<String, AnyObject>? { 
     do { 
      return try NSJSONSerialization.JSONObjectWithData(self, options: NSJSONReadingOptions(rawValue: 0)) as? Dictionary<String, AnyObject> 
     } catch let error as NSError { 
      DLog("NSData: error converting data to JSON: \n\(self.asString)\nerror: \n\(error)") 
      return nil 
     } 
    } 

} 

class NetworkOperation { 

    lazy var defaultCompletionHandler: NSURLSessionCompletionHandler = { [weak self] (data, response, error) in 
     guard let s = self where !s.cancelled else { 
      return 
     } 

     if let httpResponse = response as? NSHTTPURLResponse { 
      switch httpResponse.statusCode { 
       case 200..<300: 
        s.successResponse(data, response: response, error: error) 

       // ... 
      } 
     } else { 
      // ... 
     }    
    } 

    func successResponse(data: NSData!, response: NSURLResponse!, error: NSError!) { 
     DLog("NetworkOperation: '\(name!)' finished") 

     if let jsonDict = data.JSONDict() { 
      let json = JSON(jsonDict) 
      // process JSON 
     } 
    } 
} 

一切工作正常,但我的應用程序似乎每次解析JSON時泄漏了大量的內存。我試着做用儀器分析代,這裏是它表明:

Instruments screenshot

好像NSJSONSerialization.JSONObjectWithData是原因。但是,泄漏的內存塊是malloc_zone_malloc/malloc_zone_calloc(即不是ARC管理的),所以我看不到引用計數。

如何繼續調試此問題?

+0

你肯定有很多東西在裏面:延伸,懶惰,[弱自我],財產中的封閉,是否能讓生活更容易理解? [Brian Kernighan](https://en.wikipedia.org/wiki/Brian_Kernighan):*每個人都知道,調試比編寫程序要困難一倍。所以,如果你寫的時候你的聰明才智,你將如何去調試它?* [Kent Beck](https://en.wikipedia.org/wiki/Kent_Beck):*做最簡單的事情可能工作*。 – zaph

+0

@ zaph是的,我知道,它太複雜了:)但我有一個藉口,這個代碼的主要部分不是我自己創作的,我沒有時間重構它。 –

回答

3

這個問題的原因是夫特2.0錯誤(見的Xcode 7 release notes):

使用針對多種類型的具有作爲圖案可以導致內存泄漏開關例如,避免這種開關語句:

switch x { 
    case let a as A: ... 
    case let b as B: ... 
    case let c as C: ... 
    default: ... 
} 

重寫如果讓= x作爲使用碼A語句,而不是開關該模式執行鍵入避免內存泄漏檢查(22587077)

01?。

順便說一句,這正是SwiftyJSON在內部使用的switch語句的類型。有一個開放的問題:https://github.com/SwiftyJSON/SwiftyJSON/issues/323

這個bug已經修復Swift 2.1(根據@ zaph)。目前,該解決方案是SwiftyJSON.swift替換下面的代碼:

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"]) 
} 

有:

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"]) 
} 

(歸功於tehong

+1

注意:這已在Swift 2.1中修復。 – zaph