使用SwiftyJSON

时间:2019-03-20 01:59:31

标签: ios swift memory-leaks instruments

首先,我是仪器和内存图的新手。试图检查我的应用程序是否存在内存泄漏,然后遇到了这个问题。它是具有MVVM体系结构的类的集合,该类具有以下功能:

  1. View Controller触发View模型中的功能
  2. View Model要求网络类从Web API检索JSON
  3. 网络类成功从Web api检索数据,它使用SwiftyJson将字典转换为JSON对象,并发生内存泄漏
  4. SwiftyJSON的init函数又名JSON()/ JSON.init()发生泄漏
  5. 代码库是Objective-C和Swift的混合体,但是具有内存泄漏的类是用Swift编写的。

我做了一些研究,以下是我的发现:

  1. 创建一个新项目并复制类,并尝试重新创建问题,但没有发生内存泄漏
  2. 仅当调用闭包并将结果返回给调用方时,才会发生此问题
  3. 此泄漏也发生在具有类似代码结构的其他地方;调用闭包->闭包进行api调用->接收结果->转换为JSON->内存泄漏。另一种情况是使用Firebase SDK进行远程配置。更详细地,该函数是FIRRemoteConfig.fetch

下面的内存图和仪器的介绍,代码和屏幕截图足够多,(代码类很大,因此我只附加最重要的部分):

Memory graph image

Instrument image

视图控制器类

@objc final class HomeVC: UIViewController {
    internal lazy var viewModel = { return HomeVM() }()

    override func viewDidLoad() {
        initVM()
    }

    private func initVM() {
        viewModel.reloadPersonalization.addObserver(onChange: {[weak self] (reload) in
            if reload {
                self?.collectionView.reloadSections(IndexSet(integer: HomeSection.personalization.rawValue))
            }
        })
    }
}

查看模型类

import SwiftyJSON

class HomeVM {
    //MARK:- Observable

    let reloadPersonalization = Observable<Bool>(value: false)
    let isLoading = Observable<Bool>(value: false)

    //MARK:- Properties
    var personalizations = Personalization()

    //MARK:- Initialization
    init() {

    }

    //MARK:- Functions

    public func fetchPersonalization() {
        BaseApi.requestAPIService(apiService: MainMallService.showPersonalization, resultReceive: {

        }, success: {[weak self] (json) in
            self?.personalizations.updateProductList(json: json)
            self?.reloadPersonalization.value = true
            }, successWithError: {[weak self] (errorMsg) in
                self?.reloadPersonalization.value = false
        }, fail: {[weak self] (errorMsg) in
            self?.reloadPersonalization.value = false
        })

    }
}

网络课程

import Moya
import SwiftyJSON
import Alamofire

    class BaseApi {
        //MARK: Properties

        //MARK: Functions
        open class func requestAPIService(apiService: TargetType, resultReceive: @escaping () -> Void ,success: @escaping (_ jsonResponse: JSON) -> (), successWithError: @escaping (_ error: String) -> (), fail: @escaping (_ errorMsg: String) -> ()) {
            let provider = MoyaProvider<MultiTarget>(manager:NetworkManager.shared ,plugins: [NetworkLoggerPlugin(verbose: true)])
            let target = MultiTarget(apiService)

            provider.request(target) { result in
                resultReceive()

                switch result {
                case let .success(moyaResponse):
                    let data = moyaResponse.data
                    let json = JSON(data)
                    let apiStatus = ApiStatus.initWithJson(json: json["status"])

                    switch apiStatus.status {
                    case .Success:
                        if json["response"].exists() {
                            let jsonResponse = json["response"]
                            success(jsonResponse)
                        }

                    case .Failed:
                        successWithError(StringConst.Error.internalError)

                    case .Unkown:
                        fail(StringConst.Error.unknownError)
                    }

                case let .failure(error):
                    var errorMsg = ""

                    if error._code == NSURLErrorTimedOut {
                        errorMsg = StringConst.Connection.timeout
                    } else if error._code == NSURLErrorNotConnectedToInternet {
                        errorMsg = StringConst.Connection.noConnection
                    } else {
                        errorMsg = StringConst.Error.unknownError
                    }

                    fail(errorMsg)
                }
            }
        }
    }

此行代码上发生内存泄漏,内存图和仪器都再次指向该行;仅在调用成功块时才会发生泄漏,其他块(例如error和successWithError)不会触发内存泄漏。

let json = JSON(data)

感谢您的帮助!

0 个答案:

没有答案