我的確喜歡新聞,我遇到以下問題,例如,如果用戶上傳超過300條新聞,那麼應用程序已經佔用超過300兆字節的內存。一旦在測試中,我確實得到didReceiveMemoryWarning
,它只幫助完全清理dataSource
。我也使用Kingfisher來緩存圖像。這種情況的最佳方式是什麼?緩存第一個數據,如果用戶將返回頂部(到最新的數據),然後從緩存中加載它們,或者如果有更好的方法?謝謝。Kingfisher將數據緩存在RAM中
更新:這是新聞JSON模型。
[ 「peopleProperties」: 「numberOfPeopleDescription」: 「沒有人在這裏」, 「numberOfPeople」:0, 「availableSeats」:0], 「isPrivateStatus」:假的, 「additionalInfo」: 「注意」: 「」 ],「ownerID」:「」,「ticketsInfo」:[「tickets」:[]],「isTest」:false,「isNewPendingRequest」:false,「dateProperties」:[「isEditable」:true,「iso8601」 「,」day「:」「,」endTimeStamp「:0.0,」isFlexDate「:true,」isFlexTime「:true,」timeStamp「:0.0],」boolProperties「:[」isPartnerGeneratedCard「:false,」isAutoGeneratedCard「:true ,「isUserCreatedCard」:false,「isAdminCreatedCard」:false],「location」:[「formattedAddress」:「692 N Robertson Blvd(位於Santa Monica Blvd),美國加利福尼亞州西好萊塢90069」,「fullLocationName」 692 N Robertson Blvd「,」coordinate「:[」longitude「:-118.38528500025966,」latitude「:34.083373986214625]],」id「:」「,」photoURLsProperties「:[」placePhotoURLs「:[例如「],」placeLogoURLs「:[]],」services「:[」serviceURL「:」「,」serviceID「:」41cf5080f964a520a61e1fe3「,」index「:1],」version「:1,修道院食品&酒吧」, 「OWNERNAME」: 「」, 「手機」:[:]
更新1.有時涉及到應用程序崩潰。我的測試控制器
import UIKit
import SVProgressHUD
class CardTestTableViewController: UITableViewController {
// MARK: - Managers
fileprivate let firCardDatabaseManager = FIRCardDatabaseManager()
fileprivate let apiManager = ableCardsAPIManager()
// MARK: - API Manager's properties
fileprivate var firstCardsCount = 0
fileprivate var isSecondTypeRequestLaunch = false
/// Main cards array
fileprivate var cardsModels = [CardModel]()
fileprivate var firCardsModels = [CardModel]()
fileprivate var backendCardsModels = [CardModel]()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
definesPresentationContext = true
requestAllData()
// table view
registerCells()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(false, animated: false)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
debugPrint("didReceiveMemoryWarning")
cardsModels.removeAll()
tableView.reloadData()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if cardsModels.count > 0 {
debugPrint("cardsModels.first!.toJSON()", cardsModels.first!.toJSON(), "cardsModels.first!.toJSON()")
}
return cardsModels.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = cardTestTableViewCell(tableView, indexPath: indexPath)
let lastElement = cardsModels.count - 15
if indexPath.row == lastElement {
secondRequest(indexPath.row)
}
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 298
}
}
extension CardTestTableViewController {
fileprivate func registerCells() {
let nib = UINib(nibName: CardTestTableViewCell.defaultReuseIdentifier, bundle: Bundle.main)
tableView.register(nib, forCellReuseIdentifier: CardTestTableViewCell.defaultReuseIdentifier)
}
}
// MARK: - Cells
extension CardTestTableViewController {
fileprivate func cardTestTableViewCell(_ tableView: UITableView, indexPath: IndexPath) -> CardTestTableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CardTestTableViewCell.defaultReuseIdentifier, for: indexPath) as! CardTestTableViewCell
let card = cardsModels[indexPath.row]
cell.setupData(card)
return cell
}
}
// MARK: - Requests
extension CardTestTableViewController {
@objc fileprivate func requestAllData() {
let requestGroup = DispatchGroup()
if let topViewController = UIApplication.topViewController() {
if topViewController.isKind(of: CardViewController.self) {
SVProgressHUD.show()
}
}
firCardsModels.removeAll()
backendCardsModels.removeAll()
requestGroup.enter()
firCardDatabaseManager.getCardModelsByUserLocation(success: { [weak self] (userCardsModels) in
debugPrint("Finish +++ fir", userCardsModels.count)
self?.firCardsModels = userCardsModels
requestGroup.leave()
}) { (error) in
// TODO: - Think about it: Do not show an error, because we have cards with FourSquare
debugPrint("FIRCardDatabaseManager error", error.localizedDescription)
requestGroup.leave()
}
requestGroup.enter()
apiManager.requestCards(10, secondRequestLimit: 50, isFirstRequest: true, success: { [weak self] (cards) in
self?.backendCardsModels = cards
requestGroup.leave()
}) { (error) in
requestGroup.leave()
}
requestGroup.notify(queue: .main) { [weak self] in
guard let _self = self else { return }
_self.cardsModels.removeAll()
_self.cardsModels.append(contentsOf: _self.firCardsModels)
_self.cardsModels.append(contentsOf: _self.backendCardsModels)
self?.tableView.reloadData()
// for api manager
self?.firstCardsCount = _self.cardsModels.count
SVProgressHUD.dismiss()
}
}
fileprivate func secondRequest(_ index: Int) {
// the second request
debugPrint("swipe index", index, "firstCardsCount", firstCardsCount)
// This is for how much to the end of the deck, we ask for more cards.
let muchMoreIndex = 15
let checkNumber = firstCardsCount-1 - index - muchMoreIndex
debugPrint("checkNumber", checkNumber)
if checkNumber == 0 || checkNumber < 0 {
guard !isSecondTypeRequestLaunch else { return }
isSecondTypeRequestLaunch = true
apiManager.requestCards(0, secondRequestLimit: 50, isFirstRequest: false, success: { [weak self] (backendCards) in
DispatchQueue.main.async {
guard let _self = self else { return }
_self.cardsModels.append(contentsOf: backendCards)
_self.firstCardsCount = _self.cardsModels.count
_self.isSecondTypeRequestLaunch = false
_self.tableView.reloadData()
}
}, fail: { [weak self] (error) in
self?.isSecondTypeRequestLaunch = false
})
}
}
}
import UIKit
import Kingfisher
class CardTestTableViewCell: UITableViewCell {
@IBOutlet private weak var titleLabel: UILabel!
@IBOutlet private weak var cardImageView: UIImageView!
@IBOutlet private weak var profileImageView: UIImageView!
override func prepareForReuse() {
cardImageView.image = nil
profileImageView.image = nil
}
func setupData(_ card: CardModel) {
downloadImages(card)
setupLabelsData(card)
}
private func downloadImages(_ card: CardModel) {
if let placeAvatarURLString = card.photoURLsProperties.placePhotoURLs.first {
if let placeAvatarURL = URL(string: placeAvatarURLString) {
cardImageView.kf.indicatorType = .activity
cardImageView.kf.setImage(with: placeAvatarURL)
} else {
cardImageView.image = UIImage(named: "CardDefaultImage")
}
} else if let eventLogoURLPath = card.photoURLsProperties.placeLogoURLs.first {
if let url = URL(string: eventLogoURLPath) {
cardImageView.kf.indicatorType = .activity
cardImageView.kf.setImage(with: url)
} else {
cardImageView.image = UIImage(named: "CardDefaultImage")
}
} else {
cardImageView.image = UIImage(named: "CardDefaultImage")
}
guard card.boolProperties.isAutoGeneratedCard != true && card.boolProperties.isAdminCreatedCard != true else {
profileImageView.image = #imageLiteral(resourceName: "ProfileDefaultIcon")
return
}
let firImageDatabaseManager = FIRImageDatabaseManager()
firImageDatabaseManager.downloadCardUserProfileImageBy(card.ownerID) { [weak self] (url, error) in
DispatchQueue.main.async {
guard error == nil else {
self?.profileImageView.image = #imageLiteral(resourceName: "ProfileDefaultIcon")
return
}
guard let _url = url else {
self?.profileImageView.image = #imageLiteral(resourceName: "ProfileDefaultIcon")
return
}
self?.profileImageView.kf.indicatorType = .activity
self?.profileImageView.kf.setImage(with: _url)
}
}
}
private func setupLabelsData(_ card: CardModel) {
titleLabel.text = card.title
}
}
更新2。當我註釋掉與Kingfisher框架相關的代碼時,就沒有內存泄漏和應用程序崩潰。
使用SDWebImage。 – KKRocks
嗨@KKRocks請告訴我,在什麼翠鳥不適合?這個相同的庫只能快速寫入。接下來我想問一下,你認爲這不是一個大型數據集(目前最多可容納1000個模型)的問題。 – Alexander
您能否分享您的新聞提要數據的示例單個對象。 –