Tableview cells are visible while app is in debug but when tried to terminate app and than try to reopen the app, cells are not visible.
Approach(Which i used in my app):
lazy var contactPickerScene: ContactTabelViewController = {
guard let contactPickerScene = self.storyboard?.instantiateViewController(identifier: "ContactTabelViewController") as? ContactTabelViewController else {
return ContactTabelViewController()
}
return contactPickerScene
}()
contactPickerScene.contactDelegate = self
contactPickerScene.multiSelectEnabled = true
contactPickerScene.subtitleCellValue = .email
contactPickerScene.view.frame = self.contactListView.bounds
self.addChild(contactPickerScene)
self.contactListView.addSubview(contactPickerScene.view)
contactPickerScene.didMove(toParent: self)
public class ContactTabelViewController: UITableViewController, UISearchResultsUpdating, UISearchBarDelegate {
---------------------------
public override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem
self.title = "Contacts"
self.tableView.dataSource = self
self.tableView.delegate = self
inititlizeBarButtons()
initializeSearchBar()
registerContactCell()
fetchContacts()
}
---------------------------
}
// MARK: - Contact Operations
extension ContactTabelViewController {
func fetchContacts() {
DispatchQueue.global().async {
self.getContacts( {(contacts, error) in
if (error == nil) {
DispatchQueue.main.async(execute: {
// self.tableView.dataSource = self
// self.tableView.delegate = self
self.contactsList = contacts
self.tableView.reloadData()
})
}
})
}
}
func getContacts(_ completion: @escaping ContactsHandler) {
if contactsStore == nil {
contactsStore = CNContactStore()
}
let error = NSError(domain: "ContactPickerErrorDomain", code: 1, userInfo: [NSLocalizedDescriptionKey: "No Contacts Access"])
switch CNContactStore.authorizationStatus(for: CNEntityType.contacts) {
case CNAuthorizationStatus.denied, CNAuthorizationStatus.restricted:
DispatchQueue.main.async {
if self.contactsList.isEmpty {
self.tableView.isScrollEnabled = false
self.resultSearchController.searchBar.isHidden = true
self.tableView.setEmptyMessage("We could not fetch your contacts. Please allow contacts permission.")
}
}
case CNAuthorizationStatus.notDetermined:
contactsStore?.requestAccess(for: CNEntityType.contacts, completionHandler: { (granted, error) -> Void in
if (!granted ){
DispatchQueue.main.async(execute: { () -> Void in
completion([], error! as NSError?)
})
}
else{
DispatchQueue.global().async {
self.orderedContacts = [String: [CNContact]]()
self.getContacts(completion)
}
}
})
case CNAuthorizationStatus.authorized:
var contactsArray = [CNContact]()
let contactFetchRequest = CNContactFetchRequest(keysToFetch:[CNContactVCardSerialization.descriptorForRequiredKeys()])
contactFetchRequest.sortOrder = CNContactSortOrder.givenName
do {
try contactsStore?.enumerateContacts(with: contactFetchRequest, usingBlock: { (contact, stop) -> Void in
var key: String = "#"
if let firstLetter = contact.givenName[0..<1] , firstLetter.containsAlphabets() {
key = firstLetter.uppercased()
}
var contacts = [CNContact]()
if let segregatedContact = self.orderedContacts[key] {
contacts = segregatedContact
}
if(contactsArray.count == 0){
if !Constant.boolIsSubscribe {
contacts.append(contact)
}
}
contacts.append(contact)
self.orderedContacts[key] = contacts
contactsArray.append(contact)
})
self.sortedContactKeys = Array(self.orderedContacts.keys).sorted(by: <)
if self.sortedContactKeys.first == "#" {
self.sortedContactKeys.removeFirst()
self.sortedContactKeys.append("#")
}
completion(contactsArray, nil)
}
//Catching exception as enumerateContactsWithFetchRequest can throw errors
catch let error as NSError {
print(error.localizedDescription)
}
@unknown default:
break
}
}
}
While Debug:
After App Killed:
i want to result same as i got in debug. cell needs to load load while app running after kill from debug state.
in this issue i already spent 2 days and also create separate UItableviewcontroller but getting same result.
XCode Version 15.0
Swift 5.0
iOS 17.0
MacOS Sonoma
i am using this environment currently.
Same issue again in different scenario
i found same issue again in UITableView
in same project and history page showing me some history while device attach to system and app is running but whenever i kill app and run it’s showing blank tableview.
Logs while connected to device and run
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 146 ==> GetLoadFileFromDocumentDict()
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 2 ==> 171 ==> tableView(_:numberOfRowsInSection:)
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 2 ==> 171 ==> tableView(_:numberOfRowsInSection:)
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 340.0 ==> 262 ==> tableView(_:heightForRowAt:)
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 75.0 ==> 266 ==> tableView(_:heightForRowAt:)
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 2 ==> 171 ==> tableView(_:numberOfRowsInSection:)
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 181 ==> tableView(_:cellForRowAt:)
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 340.0 ==> 262 ==> tableView(_:heightForRowAt:)
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 181 ==> tableView(_:cellForRowAt:)
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 75.0 ==> 266 ==> tableView(_:heightForRowAt:)
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 340.0 ==> 262 ==> tableView(_:heightForRowAt:)
09:16:36: <SharingApp.HistoryViewController: 0x11a4ac770> ==> 75.0 ==> 266 ==> tableView(_:heightForRowAt:)
Logs while not connected to device and run
09:17:49: <SharingApp.HistoryViewController: 0x119563620> ==> 146 ==> GetLoadFileFromDocumentDict()
09:17:49: <SharingApp.HistoryViewController: 0x119563620> ==> 2 ==> 171 ==> tableView(_:numberOfRowsInSection:)
09:17:49: <SharingApp.HistoryViewController: 0x119563620> ==> 2 ==> 171 ==> tableView(_:numberOfRowsInSection:)
09:17:50: <SharingApp.HistoryViewController: 0x119563620> ==> 340.0 ==> 262 ==> tableView(_:heightForRowAt:)
09:17:50: <SharingApp.HistoryViewController: 0x119563620> ==> 75.0 ==> 266 ==> tableView(_:heightForRowAt:)
09:17:50: <SharingApp.HistoryViewController: 0x119563620> ==> 2 ==> 171 ==> tableView(_:numberOfRowsInSection:)
09:17:50: <SharingApp.HistoryViewController: 0x119563620> ==> 340.0 ==> 262 ==> tableView(_:heightForRowAt:)
09:17:50: <SharingApp.HistoryViewController: 0x119563620> ==> 75.0 ==> 266 ==> tableView(_:heightForRowAt:)
i don’t know why cellForRowAt
is not getting called.
HistoryViewcontroller.Swift
import UIKit
import Photos
import QuickLook
import Kingfisher
import GoogleMobileAds
struct History : Codable {
let name: String?
let data: Data?
let date: Date?
let size: Int?
let docType: URLType
}
class HistoryViewController: UIViewController {
@IBOutlet weak var tblHistory: UITableView!
var rightBarButton : UIBarButtonItem!
var arraySplitArray = [URL]()
lazy var previewItem = NSURL()
var arryValue = [URL]()
var imageLocal = [UIImage]()
var selectedIndexPath = [IndexPath]()
var boolIsNativeAdHide : Bool = false
enum Errors : Error {
case error1(str: String?)
case error2
case error3
}
override func viewDidLoad() {
super.viewDidLoad()
rightBarButton = UIBarButtonItem(title: "Delete All", style: .plain, target: self, action: #selector(didTapSelectButton(sender:)))
navigationItem.rightBarButtonItem = rightBarButton
isSmallNativeAd = false
tblHistory.register(UINib(nibName: "HistoryTableViewCell2", bundle: nil), forCellReuseIdentifier: "HistoryTableViewCell2")
tblHistory.register(UINib(nibName: "NativeAdCell", bundle: nil), forCellReuseIdentifier: "NativeAdCell")
tblHistory.dataSource = self
tblHistory.delegate = self
self.GetLoadFileFromDocumentDict()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.title = "History"
}
@objc
func didTapSelectButton(sender: AnyObject){
let refreshAlert = UIAlertController(title: "Confirmation", message: "Are you sure you want to delete history?", preferredStyle: UIAlertController.Style.alert)
refreshAlert.addAction(UIAlertAction(title: "Yes", style: .default, handler: { (action: UIAlertAction!) in
self.CleanHistory()
}))
refreshAlert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { (action: UIAlertAction!) in
print("Handle Cancel Logic here")
}))
present(refreshAlert, animated: true, completion: nil)
}
func CleanHistory(){
let fileManager = FileManager.default
let myDocuments = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
let folderURL = myDocuments.appendingPathComponent(Constant.strFolderName)
guard let filePaths = try? fileManager.contentsOfDirectory(at: folderURL, includingPropertiesForKeys: nil, options: []) else { return }
for filePath in filePaths {
try? fileManager.removeItem(at: filePath)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1){
// create the alert
let alert = UIAlertController(title: "Information", message: "History Deleted Successfully.", preferredStyle: UIAlertController.Style.alert)
// add an action (button)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
// show the alert
self.present(alert, animated: true, completion: nil)
}
self.GetLoadFileFromDocumentDict()
}
func GetLoadFileFromDocumentDict() {
self.arraySplitArray.removeAll()
self.arryValue.removeAll()
if let arrUrls = FileManager.allRecordedData() {
arryValue = arrUrls.filter({ url in
if url.lastPathComponent.contains("png") ||
url.lastPathComponent.contains("jpg") ||
url.lastPathComponent.contains("gif") ||
url.lastPathComponent.contains("tif") ||
url.lastPathComponent.contains("JPG") ||
url.lastPathComponent.contains("PNG") ||
url.lastPathComponent.contains("HEIC") ||
url.lastPathComponent.contains("WEBM") ||
url.lastPathComponent.contains("MPG") ||
url.lastPathComponent.contains("MPEG") ||
url.lastPathComponent.contains("MPE") ||
url.lastPathComponent.contains("MP4") ||
url.lastPathComponent.contains("M4P") ||
url.lastPathComponent.contains("M4V") ||
url.lastPathComponent.contains("AVI") ||
url.lastPathComponent.contains("WMV") ||
url.lastPathComponent.contains("MOV") ||
url.lastPathComponent.contains("pdf") ||
url.lastPathComponent.contains("vcf") ||
url.lastPathComponent.contains("m4a") {
return true
}else {
return false
}
})
for fileURL in arryValue {
if(fileURL.pathExtension != ""){
arraySplitArray.append(fileURL)
}
}
if arraySplitArray.count > 0 {
if !Constant.boolIsSubscribe {
arraySplitArray.insert(URL(string: "AD")!, at: 0)
}
rightBarButton.isEnabled = true
}else{
rightBarButton.isEnabled = false
}
RBLogger.log("(self) ==> (#line) ==> (#function)")
self.tblHistory.reloadData()
}
}
func deleteData(at indexPath: IndexPath) {
print(indexPath.row)
RemoveFileFromDocumentDictionary(indexPath: indexPath)
}
func RemoveFileFromDocumentDictionary(indexPath : IndexPath) {
let fileManager = FileManager.default
do {
try fileManager.removeItem(at:arraySplitArray[indexPath.row])
arraySplitArray.remove(at: indexPath.row)
self.tblHistory.reloadData()
} catch {
print(error)
}
}
}
//MARK:- Tableview Methods
extension HistoryViewController : UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
RBLogger.log("(self) ==> (arraySplitArray.count) ==> (#line) ==> (#function)")
if arraySplitArray.isEmpty {
tblHistory.setEmptyView(image: UIImage(named: "noData")!, title: "", message: "")
}else {
tblHistory.restoreView()
}
return arraySplitArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
RBLogger.log("(self) ==> (#line) ==> (#function)")
let url = arraySplitArray[indexPath.row]
if url.absoluteString == "AD" {
let nativeAdCell = tableView.dequeueReusableCell(withIdentifier: "NativeAdCell") as! NativeAdCell
if !boolIsNativeAdHide {
loadNativeAd(view: nativeAdCell.adView, isSmallNativeAd: isSmallNativeAd) {[weak self] isLoad in
DispatchQueue.main.async {
if !isLoad {
self?.boolIsNativeAdHide = true
self?.tblHistory.reloadRows(at: [IndexPath(row: indexPath.row, section: indexPath.section)], with: .none)
}else {
print("Ad already load.")
}
}
}
}
nativeAdCell.selectionStyle = .none
return nativeAdCell
}else {
guard let cell : HistoryTableViewCell2 = tableView.dequeueReusableCell(withIdentifier: "HistoryTableViewCell2") as? HistoryTableViewCell2 else {
return UITableViewCell()
}
do {
let checkVideoOrImage = self.checkURLType(inputURL: arraySplitArray[indexPath.row])
if checkVideoOrImage == "Image" {
let data = try Data(contentsOf: self.arraySplitArray[indexPath.row])
DispatchQueue.main.async {
cell.imgThumb.image = UIImage(data: data)
}
}else if checkVideoOrImage == "Video"{
cell.imgThumb.image = self.generateThumbnail(path: arraySplitArray[indexPath.row])
}else if (arraySplitArray[indexPath.row].pathExtension.lowercased() == "pdf"){
cell.imgThumb.image = UIImage.init(named: "pdf")
}else if (arraySplitArray[indexPath.row].pathExtension.lowercased() == "vcf"){
cell.imgThumb.image = UIImage.init(named: "vcf")
}else if (arraySplitArray[indexPath.row].pathExtension.lowercased() == "m4a"){
cell.imgThumb.image = UIImage.init(named: "musical")
}else {
cell.imgThumb.image = UIImage.init(named: "document")
}
cell.lblName.text = arraySplitArray[indexPath.row].lastPathComponent
let resourceValues = try arraySplitArray[indexPath.row].resourceValues(forKeys: [.fileSizeKey])
let fileSize = resourceValues.fileSize!
cell.lblSize.text = ByteCountFormatter().string(fromByteCount: Int64(fileSize))
} catch { print(error) }
let attributes = try? FileManager.default.attributesOfItem(atPath: arraySplitArray[indexPath.row].path)
if let date = attributes?[.modificationDate] {
print("File Modification date is %@", date)
let dateFormatter = DateFormatter()
let tempLocale = dateFormatter.locale
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.dateFormat = "dd-MM-yyyy"
dateFormatter.locale = tempLocale
let dateString = dateFormatter.string(from: date as! Date)
cell.lblDate.text = dateString
}
cell.btnViewClick = {(_ aCell: HistoryTableViewCell2) -> Void in
DispatchQueue.main.async {
self.previewItem = self.arraySplitArray[indexPath.row] as NSURL
let quickLookController = QLPreviewController()
quickLookController.dataSource = self
self.present(quickLookController, animated: true, completion: nil)
}
}
cell.selectionStyle = .none
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let url = arraySplitArray[indexPath.row]
if url.absoluteString == "AD" {
if boolIsNativeAdHide {
RBLogger.log("(self) ==> 0.0 ==> (#line) ==> (#function)")
return 0.0
}else{
RBLogger.log("(self) ==> (nativeAdHeight() + 40.0) ==> (#line) ==> (#function)")
return nativeAdHeight() + 40.0
}
}else {
RBLogger.log("(self) ==> 75.0 ==> (#line) ==> (#function)")
return 75.0
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let url = arraySplitArray[indexPath.row]
if url.absoluteString == "AD" {
return
}
if(tblHistory.isEditing){
selectedIndexPath.append(indexPath)
print(indexPath.row)
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let url = arraySplitArray[indexPath.row]
if url.absoluteString == "AD" {
return
}
if(tblHistory.isEditing){
selectedIndexPath.remove(at: indexPath.row)
print(indexPath.row)
}
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let url = arraySplitArray[indexPath.row]
if url.absoluteString == "AD" {
return nil
}
let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { (contextualAction, view, boolValue) in
self.deleteData(at: indexPath)
}
let swipeActions = UISwipeActionsConfiguration(actions: [deleteAction])
return swipeActions
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
}
extension HistoryViewController : QLPreviewControllerDataSource {
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return previewItem as QLPreviewItem
}
}
extension HistoryViewController {
func checkURLType(inputURL : URL) -> String {
// Most commom image types..
let imageExtensions = ["png", "jpg", "gif", "tif", "JPG", "PNG","HEIC"]
// Most cmmon video types..
let videoExtensions = ["WEBM", "MPG", "MPEG", "MPE", "MP4", "M4P", "M4V", "AVI", "WMV", "MOV"]
let url: URL? = URL(fileURLWithPath: inputURL.path)
let pathExtention = url?.pathExtension
if imageExtensions.contains(pathExtention!) {
print("Image URL History: (String(describing: url))")
return "Image"
}else if videoExtensions.contains(pathExtention!) {
print("Video URL: (String(describing: url))")
return "Video"
}else {
print("Does Not Exist: (String(describing: url))")
return ""
}
}
func generateThumbnail(path: URL) -> UIImage? {
do {
let asset = AVURLAsset(url: path, options: nil)
let imgGenerator = AVAssetImageGenerator(asset: asset)
imgGenerator.appliesPreferredTrackTransform = true
let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
let thumbnail = UIImage(cgImage: cgImage)
return thumbnail
} catch let error {
print("*** Error generating thumbnail: (error.localizedDescription)")
return nil
}
}
}
2
Answers
This 2 solution work for me
First:
i don't know why but when i tried to comment this method
heightForRowAt
thancellForRowAt
method called.Second:
Whenever i tried to set
heightForRowAt
value asUITableView.automaticDimension
Looks like this piece in
heightForRowAt indexPath:
:should be opposite – as below:
Hope it helps.