cellForItem or sizeForItem not called - iglistkit

I am trying out IGListKit for the first time but i seem to have hit a brick wall early on
lazy var collectionView: UICollectionView = {
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
collectionView.backgroundColor = .white
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.collectionView)
let updater = ListAdapterUpdater()
let adapter = ListAdapter(updater: updater, viewController: self, workingRangeSize: 0)
adapter.collectionView = self.collectionView
adapter.dataSource = self
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.frame = view.bounds
}
And
extension SocialViewController: ListAdapterDataSource {
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
// this can be anything!
return [ "Foo" as ListDiffable, "Bar" as ListDiffable]
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
return TopNewsSectionController()
}
func emptyView(for listAdapter: ListAdapter) -> UIView? {
return UIImageView(image: UIImage(named: "swords"))
}
}
class TopNewsSectionController: ListSectionController {
override func sizeForItem(at index: Int) -> CGSize {
return CGSize(width: collectionContext!.containerSize.width, height: 55)
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
return collectionContext!.dequeueReusableCell(of: TopNewsCollectionViewCell.self, for: self, at: index)
}
}
but my neither cellForItem or sizeForItem is being called
what am i doing wrong?

Try to declare adapter as a class property rather than a method property,
let updater = ListAdapterUpdater()
let adapter = ListAdapter(updater: updater, viewController: self, workingRangeSize: 0)
adapter.collectionView = self.collectionView
to
lazy var adapter: ListAdapter = {
return ListAdapter(updater: ListAdapterUpdater(), viewController: self, workingRangeSize: 0)
}()

Call adapter.performUpdatesAnimated or adapter.reloadDataWithCompletion (for the first time loading) to update

Your adapter object is destroyed when viewDidLoad returns. Try to declare it as a property of your ViewController.

Related

Swift async await: how to use with several non async delegates?

I have created this simple example, it is a UITextField with an autocompletion ability, displaying a table view showing asynchronous data that evolves as the user types in the text field.
TextField
import UIKit
protocol TextFieldDelegate {
func autocompletedComponents(
_ textField: TextField,
_ components: #escaping ([String]) -> Void
)
}
class TextField: UITextField {
var components: [String] = []
var tableView = UITableView(frame: .zero)
var autocompletionDelegate: TextFieldDelegate? { didSet { setupUI() } }
// Actions
#objc private func didUpdateText() {
autocompletionDelegate?.autocompletedComponents(self) { [weak self] components in
guard let weakSelf = self else {
return
}
weakSelf.components = components
weakSelf.tableView.reloadData()
weakSelf.updateUI()
}
}
// Event
override func becomeFirstResponder() -> Bool {
tableView.isHidden = false
return super.becomeFirstResponder()
}
override func resignFirstResponder() -> Bool {
tableView.isHidden = true
return super.resignFirstResponder()
}
// Init
override init(frame: CGRect) {
super.init(frame: frame)
internalInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
internalInit()
}
private func internalInit() {
addTarget(
self,
action: #selector(didUpdateText),
for: .editingChanged
)
}
// UI
private func setupUI() {
tableView.dataSource = self
tableView.delegate = self
tableView.showsVerticalScrollIndicator = false
tableView.removeFromSuperview()
superview?.addSubview(tableView)
}
private func updateUI() {
let tableViewHeight = Double(min(5, max(0, components.count))) * 44.0
tableView.frame = CGRect(
origin: CGPoint(
x: frame.origin.x,
y: frame.origin.y + frame.size.height
),
size: CGSize(
width: frame.size.width,
height: tableViewHeight
)
)
}
}
extension TextField: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = components[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
44.0
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
components.count
}
}
ViewController
import MapKit
import UIKit
class ViewController: UIViewController {
private var completion: (([MKLocalSearchCompletion]) -> Void)?
private var searchCompleter = MKLocalSearchCompleter()
#IBOutlet weak var textField: TextField!
override func viewDidLoad() {
super.viewDidLoad()
searchCompleter.delegate = self
textField.autocompletionDelegate = self
}
}
extension ViewController: TextFieldDelegate {
func autocompletedComponents(
_ textField: TextField,
_ components: #escaping ([String]) -> Void
) {
if completion == nil {
completion = { results in
components(results.map { $0.title })
}
}
searchCompleter.queryFragment = textField.text ?? ""
}
}
extension ViewController: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
completion?(completer.results)
}
}
In this example the view controller uses data from MapKit. Now I would like to get rid of the #escaping blocks and replace them with the new async/await syntax.
I have started rewriting the TextField code:
protocol TextFieldDelegate {
func autocompletedComponents(
_ textField: TextField
) async -> [String]
}
#objc private func didUpdateText() {
Task {
let autocompletedComponents = await autocompletionDelegate?.autocompletedComponents(self) ?? []
components = autocompletedComponents
tableView.reloadData()
updateUI()
}
}
However I am stuck in the ViewController, because I don't know what to do with the completion block I was using until now.
Thank you for your help
Here's an implementation using Combine's PassThroughSubject to send the array from MKLocalSearchCompleterDelegate to your autocompletedComponents function which then returns that array to be used in TextField
In ViewController:
class ViewController: UIViewController {
private var searchCompleter = MKLocalSearchCompleter()
var cancellables = Set<AnyCancellable>()
var publisher = PassthroughSubject<[String], Never>()
#IBOutlet weak var textField: TextField!
override func viewDidLoad() {
super.viewDidLoad()
searchCompleter.delegate = self
textField.autocompletionDelegate = self
}
}
extension ViewController: TextFieldDelegate {
func autocompletedComponents(
_ textField: TextField
) async -> [String] {
searchCompleter.queryFragment = textField.text ?? ""
return await withCheckedContinuation { continuation in
publisher
.sink { array in
continuation.resume(returning: array)
}.store(in: &cancellables)
}
}
}
extension ViewController: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
publisher.send(completer.results.map({$0.title}))
}
}
Or you could use your completion closure it would look like this:
func autocompletedComponents(
_ textField: TextField,
_ components: #escaping ([String]) -> Void
) {
return await withCheckedContinuation { continuation in
if completion == nil {
completion = { results in
continuation.resume(returning: results.map { $0.title })
}
}
searchCompleter.queryFragment = textField.text ?? ""
}
}

SWIFT UIPanGestureRecognizer failed only first time

My test app have 4 ScrollView.
UIScrollView which can scroll up/down.
UIPageViewController inside 1, which can scroll left/right.
UITableView inside one of viewController 2, can scroll up/down.
UIScrollView inside UITableViewCell on tableView 3, can scroll left/right.
https://i.stack.imgur.com/BexX3.jpg
First swipe gesture by UIScrollView 4 causes PageViewController 2 scroll instead. Second and more swipes work correct.
PanGestureRecognizer of UIScrollView 4 has a state "failed" on the first swipe.
<UIScrollViewPanGestureRecognizer: 0x7f826881fd50; state = Failed; delaysTouchesEnded = NO; view = <Tests.MyCellScroll 0x7f826802f600>; target= <(action=handlePan:, target=<Tests.MyCellScroll 0x7f826802f600>)>>
Any ideas what’s the problem or how could it be debugged?
Example
class ViewController: UIViewController {
private let vcs: [UIViewController] = [
MyVC(),
UIViewController()
]
private lazy var scroll: UIScrollView = {
let scroll = UIScrollView()
scroll.backgroundColor = .systemPink
return scroll
}()
private lazy var pageVC: UIPageViewController = {
let page = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
page.view.backgroundColor = .white
page.delegate = self
page.dataSource = self
return page
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.scroll)
self.addChild(self.pageVC)
self.scroll.addSubview(self.pageVC.view)
self.pageVC.didMove(toParent: self)
self.pageVC.setViewControllers([self.vcs[0]], direction: .forward, animated: true, completion: nil)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.scroll.frame = self.view.frame
self.scroll.contentSize = CGSize(width: self.view.frame.width, height: self.view.frame.height + 50)
self.pageVC.view.frame = CGRect(x: self.scroll.bounds.minX, y: self.scroll.bounds.minY + 250, width: self.scroll.bounds.width, height: self.scroll.contentSize.height - 250)
}
}
extension ViewController: UIPageViewControllerDataSource, UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
self.vcs.firstIndex(of: viewController) == 1 ? self.vcs[0] : nil
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
self.vcs.firstIndex(of: viewController) == 0 ? self.vcs[1] : nil
}
}
final class MyVC: UIViewController {
private lazy var table: UITableView = {
let table = UITableView()
table.register(MyCell.self, forCellReuseIdentifier: String(describing: MyCell.self))
table.delegate = self
table.dataSource = self
return table
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(self.table)
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
self.table.frame = self.view.frame
}
}
extension MyVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 5 }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { MyCell() }
}
final class MyCell: UITableViewCell {
private lazy var subview: UIView = {
let view = UIView()
view.backgroundColor = UIColor.systemBlue.withAlphaComponent(0.7)
return view
}()
private lazy var scrollView: MyCellScroll = {
let view = MyCellScroll()
return view
}()
init(){
super.init(style: .default, reuseIdentifier: nil)
self.contentView.backgroundColor = UIColor.systemOrange.withAlphaComponent(0.7)
self.contentView.addSubview(self.scrollView)
self.scrollView.addSubview(self.subview)
}
override func layoutSubviews() {
super.layoutSubviews()
let frame = self.contentView.frame
self.scrollView.frame = frame
self.scrollView.contentSize = CGSize(width: 500, height: frame.height)
self.subview.frame = CGRect(x: 16, y: 8, width: 500 - 32, height: frame.height - 16)
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
final class MyCellScroll: UIScrollView, UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
print(gestureRecognizer)
return false // 5
}
}

Trying to create new NSTextView every time the attributed string exceeds a certain height?

I'm trying to add a new NSTextView to the last index in my collection view every time the attributed string exceeds a certain bounds. The code works perfectly until the 5th item then it starts its starts creating an item every time the enter button is pressed. I'm thinking its a bug but im not sure. if any one can show me a better way to do it or improve the current code I have I would appreciate it. Below is my code:
Here is the CollectionViewItem
class DocumentItem: NSCollectionViewItem {
var itemView: DocumentTextView?
override func viewDidLoad() {
super.viewDidLoad()
self.itemView?.wantsLayer = true
// Do view setup here.
}
override func loadView() {
self.itemView = DocumentTextView(frame: NSZeroRect)
self.view = self.itemView!
}
func getView() -> DocumentTextView {
return self.itemView!
}
}
Here is the collectionView datasource
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return DocList.count
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "DocumentItem"), for: indexPath)
return item
}
Here is the NSTextView subclass
class DocumentTextView: NSTextView {
var theContainer = NSTextContainer()
var theStorage = NSTextStorage()
var theManager = NSLayoutManager()
var table = NSTextTable()
var pdfPage: PDFPage?
override init(frame frameRect: NSRect) {
super.init(frame: NSRect(origin: frameRect.origin, size: NSSize(width: 800, height: 1131 )), textContainer: theContainer)
theStorage.addLayoutManager(theManager)
theManager.addTextContainer(theContainer)
self.textContainerInset = CGSize(width: 50, height: 50)
self.textContainer?.widthTracksTextView = true
self.textContainer?.heightTracksTextView = true
self.textContainer?.lineBreakMode = .byWordWrapping
self.maxSize = NSSize(width: 800, height: 1131)
self.backgroundColor = NSColor.fromHexString("ffffff")!
self.isRichText = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here is the function bringing the bug
func textDidChange(_ notification: Notification) {
var textView = notification.object as? DocumentTextView
let numberOfItems = theDocumentOutlineView.numberOfItems(inSection: 0)
let theLastTextView = theDocumentOutlineView.item(at: numberOfItems - 1) as! DocumentItem
if textView == theLastTextView.itemView {
print(textView?.attributedString().size())
if (textView?.attributedString().size().height)! >= 1106.0 {
self.DocList.append(2)
var set = Set<IndexPath>()
set.insert(NSIndexPath(forItem: self.DocList.count - 1 , inSection: 0) as IndexPath)
theDocumentOutlineView.insertItems(at: set)
theDocumentOutlineView.scrollToItems(at: set, scrollPosition: NSCollectionView.ScrollPosition.top)
var newFirstResponder = theDocumentOutlineView.item(at: self.DocList.count - 1) as! DocumentItem
newFirstResponder.itemView?.delegate = self
self.view.window?.makeFirstResponder(newFirstResponder.itemView)
}
}
}
Here's my test project, maybe it helps. The delegate of the text view is its view controller, the NSCollectionViewItem. The view controller of the collection view also receives NSText.didChangeNotification notifications to check the length of the text. heightTracksTextView of the text container is false.
ViewController:
class ViewController: NSViewController, NSCollectionViewDataSource, NSCollectionViewDelegate {
#IBOutlet weak var collectionView: NSCollectionView!
var docList: [DocumentObject] = [DocumentObject(index: 0, string: NSAttributedString(string: "New 0"))]
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(DocumentItem.self, forItemWithIdentifier: NSUserInterfaceItemIdentifier("DocumentItem"))
NotificationCenter.default.addObserver(self, selector: #selector(textDidChange),
name: NSText.didChangeNotification, object: nil)
}
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
return docList.count
}
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
if let item = collectionView.makeItem(withIdentifier: NSUserInterfaceItemIdentifier("DocumentItem"),
for: indexPath) as? DocumentItem {
item.representedObject = docList[indexPath.item]
return item
}
return NSCollectionViewItem()
}
#objc func textDidChange(_ notification: Notification) {
if let textView = notification.object as? NSTextView {
if let theLastItem = self.collectionView.item(at: self.docList.count - 1) as? DocumentItem,
textView === theLastItem.itemView {
//if textView.attributedString().size().height >= 1106.0 {
print("\(textView.attributedString().size().height) \(textView.layoutManager!.usedRect(for: textView.textContainer!).size.height)")
if let textContainer = textView.textContainer,
let heigth = textView.layoutManager?.usedRect(for: textContainer).size.height,
heigth >= 1106.0 {
DispatchQueue.main.async {
if let window = self.view.window,
window.makeFirstResponder(nil) { // end editing of previous item
self.docList.append(DocumentObject(index: self.docList.count - 1, string: NSAttributedString(string: "New \(self.docList.count)")))
let set: Set = [IndexPath(item: self.docList.count - 1, section: 0)]
self.collectionView.insertItems(at: set)
self.collectionView.scrollToItems(at: set, scrollPosition: NSCollectionView.ScrollPosition.top)
if let newItem = self.collectionView.item(at: self.docList.count - 1) as? DocumentItem {
window.makeFirstResponder(newItem.itemView)
}
}
}
}
}
}
}
}
DocumentItem:
class DocumentItem: NSCollectionViewItem, NSTextViewDelegate {
var itemView: DocumentTextView?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
override func loadView() {
self.itemView = DocumentTextView(frame: NSZeroRect)
self.view = self.itemView!
self.itemView?.delegate = self
}
override var representedObject: Any? {
didSet {
if let item = representedObject as? DocumentObject {
itemView?.textStorage?.setAttributedString(item.string)
}
}
}
func textDidEndEditing(_ notification: Notification) {
if let item = representedObject as? DocumentObject {
item.string = itemView?.textStorage?.copy() as! NSAttributedString
}
}
}
DocumentObject:
class DocumentObject {
var index: Int
var string: NSAttributedString
init(index: Int, string: NSAttributedString) {
self.index = index
self.string = string
}
}

IGListSectionController's didUpdate and cellForItem always re-called, even though isEqual == true

Trying to implement the IGListKit library, I'm running into the issue that my cells are updated unnecessarily. I'm using a singleton adapter.dataSource with one section per row in the table.
Minimum example:
import IGListKit
class ContentItem: ListDiffable {
weak var item: Content?
weak var section: ContentSectionController?
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
return true
}
init(item: Content?) {
self.item = item
}
}
class ContentSectionController: ListSectionController {
weak var object: ContentItem?
override func didUpdate(to object: Any) {
self.object = object as? ContentItem
self.object?.section = self
// should only be called on updates
}
override func sizeForItem(at index: Int) -> CGSize {
guard let content = object?.item else {
return CGSize(width: 0, height: 0)
}
// calculate height
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell = collectionContext!.dequeueReusableCellFromStoryboard(withIdentifier: "ContentCell", for: self, at: index)
(cell as? ContentCell)?.item = object // didSet will update cell
return cell
}
override init() {
super.init()
self.workingRangeDelegate = self
}
}
extension ContentSectionController: ListWorkingRangeDelegate {
func listAdapter(_ listAdapter: ListAdapter, sectionControllerWillEnterWorkingRange sectionController: ListSectionController) {
// prepare
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerDidExitWorkingRange sectionController: ListSectionController) {
return
}
}
class ContentDataSource: NSObject {
static let sharedInstance = ContentDataSource()
var items: [ContentItem] {
return Content.displayItems.map { ContentItem(item: $0) }
}
}
extension ContentDataSource: ListAdapterDataSource {
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
return items
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
return ContentSectionController()
}
func emptyView(for listAdapter: ListAdapter) -> UIView? {
return nil
}
}
/// VC ///
class ContentViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let updater = ListAdapterUpdater()
adapter = ListAdapter(updater: updater, viewController: self, workingRangeSize: 2)
adapter.collectionView = collectionView
adapter.dataSource = ContentDataSource.sharedInstance
}
var adapter: ListAdapter!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
adapter.performUpdates(animated: true)
}
// ...
}
On every view appear I call adapter.performUpdates(animated: true), which should never update the cells since isEqual is overridden with true. Nonetheless, all cells' didUpdate is triggered, calling cellForItem again too.
IGListKit requires both diffIdentifier and isEqual to be implemented with the IGListDiffable protocol in order to compare the identity/equality of two objects. (You're missing the diff identifier in your model).
My understanding is that under the hood, ListKit checks to see if the two diff identifiers of the objects are equal, if they are THEN it moves on to comparing them with isEqual.
Resources:
IGListKit Best Practices
IGListDiffable Protocol Reference

How to deinit CollectionView class

In my project has 2 ViewControllers (ViewController and DetailViewController). On the first there are table view in UIScrollview. On the second - buttons in UICollectionView with images and links. When i popup in DetailViewController many times, the app starts slow down, and i see the leak memory on graph. Also in Debug memory i see 18 object of CollectionViewCell and 3 DetailViewController, First leak of CellProps i solve by:
override func viewDidDisappear(_ animated: Bool) {
btnArray.removeAll()
How to solve this memory leak?
ViewController.swift
import UIKit
import BetterSegmentedControl
import Firebase
class ViewController: UIViewController, UIScrollViewDelegate, UITableViewDelegate {
var ICOListGoingOn = [ICOs] ()
var ICOListEnded = [ICOs] ()
var ICOListnotstarted = [ICOs] ()
#objc func reload(n: NSNotification) {
SaveLikedArray()
self.icoArraySort()
let slide = SlideView(frame: CGRect(x: view.frame.width * CGFloat(0), y: 0, width: view.frame.width, height: slideScrollView.frame.height))
slide.ICO = ICOListLiked
slide.delegate = self
slideScrollView.addSubview(slide)
}
extension ViewController: SlideViewDelegate{
func tableCellSelected(tableView: UITableView, indexPath: IndexPath, ico: ICOs) {
// print("Table tag : \(tableView.tag) Selcted Row : \(indexPath.row) Selected Value : \(ico)")
if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DetailViewController") as? DetailViewController{
controller.ICO = ico
ICOId = ico.ICOId
self.navigationController?.pushViewController(controller, animated: true)
}
}
}
CollectionViewCell.swift
import UIKit
class CellProps {
var image: UIImage!
var url: String!
init (image: UIImage, url: String) {
self.image = image
self.url = url
}
deinit {
print("CellProps")
}
}
protocol CollectionViewCellDelegate {
func didButtonClick(url: String)
}
class CollectionViewCell: UICollectionViewCell {
var delegate: CollectionViewCellDelegate!
weak var CellItem: CellProps!
#IBOutlet weak var btnICONOutlet: UIButton!
#IBAction func btnICONAction(_ sender: Any) {
delegate?.didButtonClick(url: CellItem.url)
}
func setCell(cell: CellProps) {
CellItem = cell
CellItem.url = cell.url
btnICONOutlet.setImage(cell.image, for: .normal)
}
deinit {
print("CollectionViewCell")
}
}
DetailViewController.swift
import UIKit
class DetailViewController: UIViewController {
var ICO: ICOs!
var btnArray: [CellProps] = []
var timer: Timer?
#IBOutlet weak var outCollectioView: UICollectionView!
#IBOutlet weak var btnLike: LikeButton!
#IBAction func btnLikeAction(_ sender: Any) {
if !btnLike.isOn {
let ind = CountLikedArray(id: ICO.ICOId)
if ind != -1 {
ICOListLiked.remove(at: ind)
lblLike.text = "Вы еще не лайкнули проект"
}
}
if btnLike.isOn {
let ind = CountLikedArray(id: ICO.ICOId)
if ind == -1{
ICOListLiked.append(self.ICO)
lblLike.text = "Вам нравится проект"
}
}
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "del"), object: nil)
}
func FillButtonArray () {
for value in ICO.news.values {
var btn : CellProps!
if value.lowercased().range(of:"t.me") != nil {
btn = CellProps(image: #imageLiteral(resourceName: "telegram"), url: value)
}
else if value.lowercased().range(of:"bitcointalk.org") != nil {
btn = CellProps(image: #imageLiteral(resourceName: "bitcoin"), url: value)
} else {
btn = CellProps(image: #imageLiteral(resourceName: "link"), url: value)
}
btnArray.append(btn)
}
}
deinit {
print("deinit detail")
}
override func viewDidDisappear(_ animated: Bool) {
btnArray.removeAll()
timer = nil
outCollectioView = nil
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension DetailViewController: UICollectionViewDelegate, UICollectionViewDataSource, CollectionViewCellDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return btnArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let ICONs = btnArray[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.setCell(cell: ICONs)
cell.delegate = self
return cell
}
func didButtonClick(url: String) {
let ICONURL = URL (string: url)!
UIApplication.shared.open(ICONURL as URL)
}
}
if i debug memory graph there are 3 DatailViewController, and 18 CollectionViewCell
I found lazy way to solve self of my problem, it's
outCollectioView.removeFromSuperview()
btnLike.removeFromSuperview()
But DetailViewController still increasing (((