2015-10-08 81 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