Мое текущее назначение - расширение клавиатуры iOS, которое, среди прочего, предлагает все поддерживаемые iOS Emoji (да, я знаю, что iOS имеет встроенную клавиатуру Emoji, но цель состоит в том, чтобы включить ее в расширение клавиатуры).
Для этого макета Emoji, который в основном должен быть просмотром прокрутки со всеми emojis в нем в порядке сетки, я решил использовать UICollectionView, поскольку он создает только ограниченное количество ячеек и повторно использует их. (Есть довольно много emojis, более 1 000.) Эти ячейки просто содержат UILabel, который содержит emoji в качестве своего текста, с GestureRecognizer, чтобы вставить вытащенный Emoji.
Однако, когда я просматриваю список, я вижу, как использование памяти взрывается где-то около 16-18 МБ до более 33 МБ. Хотя это еще не вызывает предупреждение о памяти на моем iPhone 5, оно может также появляться на других устройствах, поскольку расширения приложений предназначены только для очень редкого количества ресурсов.
EDIT. Иногда я получаю предупреждение о памяти, в основном при переключении на "нормальную" раскладку клавиатуры. В большинстве случаев использование памяти уменьшается при 20 Мбайт при переключении, но не всегда.
Как уменьшить объем памяти, используемый этим макетом Emoji?
class EmojiView: UICollectionViewCell {
//...
override init(frame: CGRect) {
super.init(frame: frame)
self.userInteractionEnabled = true
let l = UILabel(frame: self.contentView.frame)
l.textAlignment = .Center
self.contentView.addSubview(l)
let tapper = UITapGestureRecognizer(target: self, action: "tap:")
self.addGestureRecognizer(tapper)
}
override func prepareForReuse() {
super.prepareForReuse()
//We know that there only is one subview of type UILabel
(self.contentView.subviews[0] as! UILabel).text = nil
}
}
//...
class EmojiViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
//...
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
//The reuse id "emojiCell" is registered in the view init.
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("emojiCell", forIndexPath: indexPath)
//Get recently used emojis
if indexPath.section == 0 {
(cell.contentView.subviews[0] as! UILabel).text = recent.keys[recent.startIndex.advancedBy(indexPath.item)]
//Get emoji from full, hardcoded list
} else if indexPath.section == 1 {
(cell.contentView.subviews[0] as! UILabel).text = emojiList[indexPath.item]
}
return cell
}
//Two sections: recently used and complete list
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 2
}
}
let emojiList: [String] = [
"\u{1F600}",
"\u{1F601}",
"\u{1F602}",
//...
// I can't loop over a range, there are
// unused values and gaps in between.
]
Пожалуйста, дайте мне знать, если вам нужно больше кода и/или информации.
Изменить: я предполагаю, что iOS сохраняет отображаемый emojis где-то в памяти, несмотря на то, что перед повторным использованием текст был nil
. Но я могу быть совершенно неправым...
РЕДАКТИРОВАТЬ. Как предложил JasonNam, я запускал клавиатуру с помощью инструмента Xcode Leaks. Там я заметил две вещи:
-
VM: CoreAnimation
при прокрутке увеличивается примерно до 6-7 МБ, но я думаю, это может быть нормально при прокрутке списка коллекций. -
Malloc 16.00KB
, начиная с значения в килобайтах, при прокрутке по всему списку увеличивается до 17 МБ, поэтому выделяется много памяти, но я не вижу ничего на самом деле используя.
Но никаких утечек не сообщалось.
EDIT2: я только что проверил с помощью CFGetRetainCount
(который все еще работает при использовании ARC), что объекты String не имеют ссылок, оставшихся после установки значения nil в prepareForReuse
.
Я тестирую iPhone 5 с iOS 9.2, но проблема также возникает в симуляторе с использованием iPhone 6s Plus.
EDIT3: у кого-то была такая же проблема здесь, но из-за странного названия я не нашел его до сих пор, Кажется, единственным решением является использование UIImageViews с UIImages в списке, так как UIImages в UICollectionView правильно выпущены при повторном использовании ячеек.