为什么我的应用程序由于内存问题而崩溃?

时间:2018-12-09 09:46:19

标签: ios swift memory crash retain-cycle

我正在处理其他开发人员创建的应用程序。这是一个完整的应用程序,并且具有很多viewControllers,变量和出口。

从服务器(例如200个)加载太多图像后,我一直崩溃。我仅在“打印区域”中收到此消息:“应用由于内存问题而终止”。

我使用库“ SDWebImage”来加载图像。我尝试使用“仪器分配”和“泄漏”来查找内存泄漏。我还使用了Memory Graph Debugger,但没有一个在我的应用程序中显示泄漏。

然而,当我弹出视图控制器(DetailVC)时,它永远不会触发deinit方法,在这种情况下,我会在该方法中放置一条要打印的消息。

我搜索了很多内容,没有发现任何问题。我在Stackoverflow上看过这些:

App Extension "Terminated due to memory issue"

App terminated due to memory issue

在搜索过程中,我反复看到以下响应,即视图控制器必须由另一个视图控制器引用,并且该视图控制器(DetailVC)强烈引用另一个视图控制器。

我找不到这种情况,尽管视图控制器的文件太大,我可能错过了一些东西。

由于该文件确实很大,因此很难遍历该应用程序并查找强引用和弱引用。

有没有一种简单的方法(或很难解决)找到罪魁祸首并解决我的问题。

谢谢

该代码巨大(95000个字符),并且包含敏感信息,因此不适合在此处发布。尽管我可以将它的一部分张贴出来,如果您需要的话。

这是DetailVC viewDidLoad的代码:

import UIKit
import FTIndicator
import Cosmos
import Firebase
import MapKit
import YouTubePlayer

//MARK:- Gallery Collection Cell
class GalleryCollectionCell:UICollectionViewCell
{
    @IBOutlet weak var imgViewShop: UIImageView!

    override func awakeFromNib()
    {
        super.awakeFromNib()
    }
}

//MARK:- Service Collection Cell
class ServiceCollectionCell:UICollectionViewCell
{
    @IBOutlet weak var imgViewService: UIImageView!
    @IBOutlet weak var lblService: UILabel!

    override func awakeFromNib()
    {
        super.awakeFromNib()
    }
}



@IBAction func btnBackAction(_ sender: Any)
    {
        self.navigationController?.popViewController(animated: true)
        SDImageCache.shared().clearMemory()
        SDImageCache.shared().clearDisk()

    }


//MARK:- Detail Main Class
class DetailVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout,UITableViewDataSource, UITableViewDelegate,RateFinalDelegate, PhotoDicDelegate
{
    //MARK:- Outlets
    @IBOutlet weak var tblViewRate: UITableView!
    @IBOutlet weak var tblViewService: UITableView!
    @IBOutlet weak var lblServices: UILabel!
    @IBOutlet weak var collViewGallery: UICollectionView!
    //@IBOutlet weak var collViewService: UICollectionView!
    @IBOutlet weak var constTableViewHeight: NSLayoutConstraint!
    @IBOutlet weak var constTlbViewServiceHeight: NSLayoutConstraint!
    @IBOutlet weak var imgViewShop: UIImageView!
    @IBOutlet weak var lblShopName: UILabel!
    //@IBOutlet weak var lblShopNameDetail: UILabel!
    @IBOutlet weak var btnFavourites: UIButton!
    @IBOutlet weak var viewStar: CosmosView!
    @IBOutlet weak var lblReviewCount: UILabel!
    @IBOutlet weak var btnShopStatus: UIButton!
    @IBOutlet weak var lblShopOnline: UILabel!
    // @IBOutlet weak var lblDetailText: UILabel!
    @IBOutlet weak var btnShopRate: UIButton!

    @IBOutlet weak var lblShopAddress: UILabel!
    @IBOutlet weak var lblShopWebsite: UILabel!
    @IBOutlet weak var lblShopView: UILabel!

    @IBOutlet weak var lblShopOpenStatus: UILabel!
    //@IBOutlet weak var lblPhone1: UILabel!
    @IBOutlet weak var lblShopDetail: UILabel!

    //    @IBOutlet weak var btnFacebook: UIButton!
    //    @IBOutlet weak var btnSnapchat: UIButton!
    //    @IBOutlet weak var btnInstagram: UIButton!
    //    @IBOutlet weak var btnTwitter: UIButton!
    //    @IBOutlet weak var btnYoutube: UIButton!
    //    @IBOutlet weak var btnVivo: UIButton!
    //    @IBOutlet weak var btnGoogle: UIButton!

    @IBOutlet weak var lblSat: UILabel!
    @IBOutlet weak var lblSun: UILabel!
    @IBOutlet weak var lblMon: UILabel!
    @IBOutlet weak var lblTues: UILabel!
    @IBOutlet weak var lblWed: UILabel!
    @IBOutlet weak var lblThru: UILabel!
    @IBOutlet weak var lblFri: UILabel!

    @IBOutlet weak var lblSatText: UILabel!
    @IBOutlet weak var lblSunText: UILabel!
    @IBOutlet weak var lblMonText: UILabel!
    @IBOutlet weak var lblTuesText: UILabel!
    @IBOutlet weak var lblWedText: UILabel!
    @IBOutlet weak var lblThruText: UILabel!
    @IBOutlet weak var lblFriText: UILabel!

    @IBOutlet weak var lblworkingHour: UILabel!
    @IBOutlet weak var lblGallery: UILabel!
    @IBOutlet weak var lblReviews: UILabel!
    @IBOutlet weak var btnSeeMore: UIButton!
    @IBOutlet weak var btnBack: UIButton!

    @IBOutlet weak var viewMain: UIView!
    @IBOutlet weak var viewSuper: UIView!
    @IBOutlet weak var viewService: UIView!

    @IBOutlet weak var btnWebsite: UIButton!
    @IBOutlet weak var btnPhone1: UIButton!
    @IBOutlet weak var btnPhone2: UIButton!
    @IBOutlet weak var btnPhone3: UIButton!
    @IBOutlet weak var constPhone1Height: NSLayoutConstraint!
    @IBOutlet weak var constPhone2Height: NSLayoutConstraint!
    @IBOutlet weak var constPhone3Height: NSLayoutConstraint!
    @IBOutlet weak var constPhoneViewHeight: NSLayoutConstraint!

    @IBOutlet weak var constViewScrollHeight: NSLayoutConstraint!

    @IBOutlet weak var scrollSocial: UIScrollView!
    // @IBOutlet weak var btnSocialLink: UIButton!
    @IBOutlet weak var btnGallery: UIButton!
    @IBOutlet weak var constViewServiceHeight: NSLayoutConstraint!

    //For Photo Class

    @IBOutlet weak var tblViewHeader: UITableView!
    @IBOutlet weak var switchGallery: UISwitch!
    @IBOutlet weak var constTableViewGalleryHeight: NSLayoutConstraint!
    var albumListArray = [AlbumListData]()

    //For Video Class

    @IBOutlet weak var collectionViewVideos: UICollectionView!
    @IBOutlet weak var constCollViewVideoHeight: NSLayoutConstraint!
    var videoDataArray = [VideoListData]()
    var switchStatus = Bool()

    //MARK:- Variables
    let globalConstants = GlobalConstants()
    var UserData = UserDataValue()
    var reviewDataArray = [Review]()
    var galleryDataArray = [Gallery]()
    var serviceDataArray = [Service]()
    var ShopId = String()
    var favStatus = String()
    var ShopStatus = String()
    var Latitude = String()
    var Longitude = String()
    var strFacebook = String()
    var strInstagram = String()
    var NotifyId = String()
    var strTwitter = String()
    var strSnapchat = String()
    var strYoutube = String()
    var strGoogle = String()
    var strVimeo = String()
    var chatStatus = Bool()
    var isfirstTime = Bool()
    var receiverId = ""
    var receiverImage = ""
    var receiverName = ""
    var strWebsite = ""
    var shopOwnerId = ""
    var ShopUnqueId = ""
    var HideChatStatus = ""
    var IsChatCreateScreen = ""
    var strPhone1Number = String()
    var strPhone2Number = String()
    var strPhone3Number = String()
    var RateText = Bool()
    var ShopDeliveryServiceItself = Bool()
    var CitySelectedId = String()
    var OneToOneChatUserData : NSDictionary = [:]
    var ShopString = "1159,1160,1162,1166,1167,1176,1178,1179,1180,1182,1184,1185,1186,1187,1188,1189,1190,1191,1192,1193,1194,1199,1202,1203,1206,1208,1209,1210,1214,1216,1217,1218,1224,1225,1227,1230,1232,1233,1234,1235,1236,1238,1239,1240,1242,1243,1244,1245,1246,1247,1248,1250,1252,1253,1255,1258,1259,1263,1264,1265,1266,1269,1270,1272,1275,1276,1277,1278,1279,1280,1281,1282,1283,1285,1298,1299,1302";

    //MARK:- View Life Cycle

    override func viewDidLoad()
    {
        super.viewDidLoad()
//        collViewGallery.dataSource = self
//        collViewGallery.delegate = self
        //        collViewService.dataSource = self
        //        collViewService.delegate = self

        btnShopStatus.setTitle("  CHAT".localiz(), for: .normal)
        btnSeeMore.setTitle("See More".localiz(), for: .normal)
        btnShopRate.setTitle("RATE".localiz(), for: .normal)
        btnGallery.setTitle("Gallery".localiz(), for: .normal)

        lblworkingHour.text = "Working Hours:".localiz()
        lblServices.text = "Services".localiz()
        lblGallery.text = "Gallery".localiz()
        lblReviews.text = "REVIEWS".localiz()


        //lblDetailText.text = "DETAILS".localiz()
        lblSatText.text = "Saturday".localiz()
        lblSunText.text = "Sunday".localiz()
        lblMonText.text = "Monday".localiz()
        lblTuesText.text = "Tuesday".localiz()
        lblWedText.text = "Wednesday".localiz()
        lblThruText.text = "Thursday".localiz()
        lblFriText.text = "Friday".localiz()

        viewStar.settings.fillMode = .precise
        self.navigationItem.title = globalConstants.detailText
        tblViewRate.register(UINib(nibName: "RateTableVCell", bundle: nil), forCellReuseIdentifier: "RateTableVCell")

        tblViewService.register(UINib(nibName: "ServiceTableCell", bundle: nil), forCellReuseIdentifier: "ServiceTableCell")

        tblViewHeader.register(UINib(nibName: "SubCatHeaderTVC", bundle: nil), forCellReuseIdentifier: "SubCatHeaderTVC")
        tblViewHeader.dataSource = self
        tblViewHeader.delegate = self
        tblViewHeader.estimatedRowHeight = 120
        tblViewHeader.rowHeight = UITableViewAutomaticDimension

        tblViewService.dataSource = self
        tblViewService.delegate = self
        tblViewService.estimatedRowHeight = 50
        tblViewService.rowHeight = UITableViewAutomaticDimension
        self.constTlbViewServiceHeight.constant = 20

        collectionViewVideos.register(UINib(nibName: "VideoCollViewCell", bundle: nil), forCellWithReuseIdentifier: "VideoCollViewCell")
        collectionViewVideos.dataSource = self
        collectionViewVideos.delegate = self
        collectionViewVideos.reloadData()

        switchStatus = false
        switchGallery.setOn(false, animated: true)

        //self.constViewServiceHeight.constant = 20

        tblViewRate.dataSource = self
        tblViewRate.delegate = self
        tblViewRate.estimatedRowHeight = 100
        tblViewRate.rowHeight = UITableViewAutomaticDimension
        //self.constTableViewGalleryHeight.constant = 20

        self.constTableViewHeight.constant = 20

//        self.tblViewHeader.isHidden = false
//        self.collectionViewVideos.isHidden = true

        //  self.constCollectionViewHeight.constant = 30
        ShopStatus = ""
        self.addBackButton()
        UserDefaults.standard.set(ShopId, forKey: "ShopValueId")
        UserDefaults.standard.synchronize()
        isfirstTime = true

        viewSuper.backgroundColor = UIColor.lightGray
        viewMain.isHidden = true
        if LanguageManger.shared.currentLanguage == .en
        {
            lblServices.textAlignment = .left
            btnBack.setImage(UIImage(named:"back"), for: .normal)
        }
        else
        {
            lblServices.textAlignment = .right
            btnBack.setImage(UIImage(named:"ReverseBack"), for: .normal)
        }
        //        if KAppDelegate.isUserLoggedIn()
        //        {
        //            let userDic = UserDefaults.standard.value(forKey: "UserData") as!  [String:Any]
        //            self.UserData = UserDataValue.init(fromDictionary: userDic)
        //            UserId = self.UserData.id!
        //            UserName = self.UserData.name!
        //        }
        if KAppDelegate.isUserLoggedIn()
        {
            let userDic = UserDefaults.standard.value(forKey: "UserData") as!  [String:Any]
            self.UserData = UserDataValue.init(fromDictionary: userDic)
            CitySelectedId = self.UserData.city!
        }
        else
        {
            if UserDefaults.standard.value(forKey: "CitySelectedId") != nil
            {
                CitySelectedId = UserDefaults.standard.value(forKey: "CitySelectedId") as! String
            }
            else
            {
                CitySelectedId = "1"
            }
        }
        ShopDetailAPIMethod()
    }

    override func viewWillAppear(_ animated: Bool)
    {
        self.navigationController?.navigationBar.isHidden = true
    }

    override func viewWillDisappear(_ animated: Bool)
    {
        self.IsChatCreateScreen = ""
        self.navigationController?.navigationBar.isHidden = false
    }

    //    override var preferredStatusBarStyle: UIStatusBarStyle
    //    {
    //        return .default
    //    }

    //MARK:- Photo Dic Delegate Method


    //MARK:- CreateNewChat Method





}

这是实例化DetailVC的方法:

 @objc func methodOfNotification(notification: Notification)
    {
        if UserDefaults.standard.value(forKey: "ShopValueId") != nil
        {
            let detailVC = self.storyboard?.instantiateViewController(withIdentifier: "DetailVC") as! DetailVC
            detailVC.ShopId = UserDefaults.standard.value(forKey: "ShopValueId") as! String
            self.navigationController?.pushViewController(detailVC, animated: true)
        }
    }

这是场景:

我在subCategoryVC中,我单击collectionView单元格,这将实例化DetailVC。在DetailVC中,我单击seeAll按钮以将图像加载到集合视图中(这是通过SDWebImage使用以下方法完成的:

l

let imageStringURL = ShopDetailData.coverImage!
            imgViewShop.sd_setShowActivityIndicatorView(true)
            imgViewShop.sd_setIndicatorStyle(.gray)
            imgViewShop.sd_setImage(with: NSURL(string:imageStringURL)! as URL, placeholderImage:UIImage(named:"noimage") , options: .refreshCached, completed: nil) 

当我单击btnBack(后退按钮)并使用navigationContrller.popViewController()弹出视图控制器时,应该在deinit消息中打印“打印区域”,但这永远不会发生。

此外,当我打开2或3个detailVC并按seeAll按钮时,应用程序崩溃,并且“打印区域”显示

  

“应用由于内存问题而终止”。

我只是用Instruments检查内存泄漏。事实证明有一个泄漏,并包含以下详细信息:

泄漏的对象= _swiftStringStorage<UInt16> 负责任的图书馆= libswiftCore.dylib 负责任的框架= swift_slowAlloc

2 个答案:

答案 0 :(得分:0)

应用允许有限的内存。我想在800mb之后,应用因内存问题而关闭。这不是一种为一个控制器下载200个映像的真实方法,但是您可以将Tableque与dequereuaseble和sdwebimage或kingfisher一起使用。您也可以使用缩略图,因为您不需要在imageview中显示1 mb的图像,这不是不必要的。

答案 1 :(得分:0)

您可能有一个保留周期。这意味着您的ViewController的某些子视图对ViewController本身或对ViewController的另一个对象具有很强的引用。发生这种情况时,即使您弹出ViewController,它也不会被破坏,直到子视图被破坏为止,而当ViewController存在时,子视图将永远不会被破坏。

如果是这种情况,解决方案将在子视图中搜索此循环引用,然后在引用ViewController的变量中添加“弱”。搜索在变量中将“自我”分配给变量的位置或在机柜中使用“自我”的位置可能会有所帮助。