Почему происходит сбой приложения из-за проблем с памятью? - PullRequest
0 голосов
/ 09 декабря 2018

Я имею дело с приложением, созданным другим разработчиком.Это законченное приложение, в котором есть много viewControllers, переменных и выходов.

Я получаю сбой после того, как загружаю слишком много изображений с сервера (например, 200).Я получаю только это сообщение в «области печати»: «Приложение закрыто из-за проблемы с памятью».

Я использую библиотеку "SDWebImage" для загрузки изображений.И я попытался найти утечку памяти, используя Распределение инструментов и Утечки.Я также использовал Memory Graph Debugger, и ни один из них не показывает утечки в моем приложении.

Тем не менее, когда я открываю View Controller (DetailVC), он никогда не запускает метод deinit, где я помещаю сообщение для печати, когда это происходит..

Я много искал, чтобы не пропасть.Я смотрел на них в Stackoverflow:

Расширение приложения "Завершено из-за проблемы с памятью"

Приложение завершено из-за проблемы с памятью

В ходе моего поиска я неоднократно получал ответ, что на контроллер представления должен ссылаться другой контроллер представления, а этот контроллер представления (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» должно быть напечатано в «области печати», но этого не происходит.кнопка seeAll, приложение вылетает, и в «области печати» отображается

«приложение прервано из-за проблемы с памятью».

Я просто использовал инструменты для проверки утечки памяти.одна утечка, как выясняется, и с этими деталями:

утечка объекта = _swiftStringStorage<UInt16> ответственная библиотека = libswiftCore.dylib ответственный кадр = swift_slowAlloc

Ответы [ 2 ]

0 голосов
/ 09 декабря 2018

У вас, вероятно, есть цикл сохранения.Это означает, что некоторые из подпредставлений вашего ViewController имеют строгую ссылку на сам ViewController или на другой объект, который имеет строгую ссылку на ViewController.Когда это происходит, даже если вы активируете ViewController, он не будет уничтожен, пока не будет уничтожено подпредставление, которое никогда не будет уничтожено, пока существует ViewController.

Если это ваш случай, решением будет поиск этой циклической ссылки в ваших подпредставлениях и добавление «слабого» в переменную, которая ссылается на ViewController.Поиск мест, в которых вы присваиваете «self» переменной или используете «self» внутри корпуса, может помочь.

0 голосов
/ 09 декабря 2018

Приложения позволяют ограничить память.Я думаю, после 800 МБ приложение закрывается из-за проблемы с памятью.Это неверный способ загрузки 200 изображений для одного контроллера, но вы можете использовать его с таблицами в режиме dequereuaseble и sdwebimage или kingfisher.Также вы можете использовать уменьшенные изображения, потому что вам не нужно показывать изображение размером 1 МБ в режиме просмотра изображений, в этом нет необходимости.

...