When I want to make an UITableView inside of an ViewController.
I have made all exactly as in a tutorial in which it worked, but I got this Error "Thread one signal SIGABRT" on class AppDelegate: UIResponder, UIApplicationDelegate { in AppDelegate.swift.
I have recently asked this question with all codes before, but every answer said, they need more information.
So i have made the whole Xcode Project new and I have filmed it with Screenium.
Here is the video (10 minutes; 53 Megabyte) https://workupload.com/file/24NNW68.
You must give in the Password
ThePassword
Then there is the information of the "video.mov". Click on the below (blue) download, the abowe is advertising.
For people who don't want to see the video (I've made it when I was 14, so my voice is a bit high: Here is the complete code:
AppDelegate.swift:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var Label1multi = ["TableView","Alarm Clock","Green","Book"]
var Label2multi = ["Pen", "1 Euro","Red","Mobile Phone"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! THISTableViewCell
cell.Label1.text = Label1multi[indexPath.row]
cell.Label2.text = Label2multi[indexPath.row]
return cell
}
}
THISTableViewCell.swift:
import UIKit
class THISTableViewCell: UITableViewCell {
#IBOutlet weak var Label1: UILabel!
#IBOutlet weak var Label2: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
But I've found the failure: When I remove The Outlet TableView - DataSource I don't get the error, but I only get empty cells in the TableView.
I have watched your video. I think the mistake is a small one. You need to set the reuse identifier for your custom cell to be "cell" in the attributes inspector. You use it correctly in this method:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! THISTableViewCell
cell.Label1.text = Label1multi[indexPath.row]
cell.Label2.text = Label2multi[indexPath.row]
return cell
}
Select the cell in main.storyboard and select the attributes inspector. Enter "cell" in the "identifier" box.
Related
I have a UIView which displays some information such as a user's Name and more, including a list of objects that all get pulled from my database. This works fine.
However, I now have a ViewController that gets presented on top of the current ViewController. In this presented ViewController, I am adding Data to my Database. When dismissing that view, I want the original ViewController to update all of its content to be up to date.
Right now, all my views are getting layedout in ViewDidLoad, meaning that they only really get loaded once and don't reload later on. I have managed to update Layout by calling self.view.layoutIfNeeded(), but if I understand correctly, this only updates constraint. Of course, I could call a new init of my original view controller. This would make it reload, but I would like to avoid that.
Another Idea I had was to set up all my content in the ViewWillAppear, which should maybe then update anytime my view controller is about to be visible. However, I don't know how to go about doing this. Can I just move all my setup code to viewWillAppear? Does this have any disadvantages?
TLDR: Is there a way to update a stackview with new elements without having to reload the full ViewController over ViewWillAppear?
The UITableView element works very smoothly with database data. If you fetch the data from your database inside viewDidLoad in your first view controller, and store it in an array, the UITableView (if you set up its dataSource correctly) will automatically populate the table with the new values from the second view controller. With this method, there is no need to use ViewWillAppear at all.
It sounds like as of now, you're using Views (inside a VStack)? to display individual objects from the database. If you want to keep whatever custom style/layout you're using with your views, this can be done by defining a custom subclass of UITableViewCell and selecting the "Also create XIB file" option. The XIB file lets you customize how the cells in your UITableView look.
Here is a simple example to show the database values in the first view controller automatically updating. I didn't include the custom XIB file (these are all default UITableViewCells), to keep it streamlined.
FIRST VIEW CONTROLLER
import UIKit
import CoreData
class ViewController: UIViewController {
#IBOutlet weak var dataTable: UITableView!
var tableRows: [DataItem] = []
func loadData() {
let request: NSFetchRequest<DataItem> = DataItem.fetchRequest()
do {
tableRows = try Global_Context.fetch(request)
} catch {
print("Error loading data: \(error)")
}
}
override func viewDidLoad() {
super.viewDidLoad()
dataTable.dataSource = self
loadData()
}
#IBAction func goForward(_ sender: UIButton) {
self.performSegue(withIdentifier: "toSecond", sender: self)
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableRows.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "dataTableCell", for: indexPath)
cell.textLabel?.text = tableRows[indexPath.row].name
return cell
}
}
let Global_Context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func saveContext () {
if Global_Context.hasChanges {
do {
try Global_Context.save()
} catch {
let nserror = error as NSError
print("Error saving database context: \(nserror), \(nserror.userInfo)")
}
}
}
SECOND VIEW CONTROLLER:
import UIKit
import CoreData
class AddViewController: UIViewController {
#IBOutlet weak var itemEntry: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
itemEntry.delegate = self
}
#IBAction func addNewItem(_ sender: UIButton) {
let newDataItem = DataItem(context: Global_Context)
newDataItem.name = itemEntry.text
saveContext()
}
#IBAction func goBack(_ sender: UIButton) {
self.performSegue(withIdentifier: "toFirst", sender: self)
}
}
extension AddViewController: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.endEditing(true)
return true
}
}
Main.storyboard:
Once you set up your view controller as a UITableViewDataSource (as in the example code), the table view should make things simpler by eliminating any need to manually manage individual Views.
Is this the functionality you were looking for? (Note about the example: it was set up in Xcode with "Use Core Data" enabled.)
Here is a link to the official documentation:
https://developer.apple.com/documentation/uikit/uitableview
I have a MKMapView in one of my static cells. Instead of being able move the map around, I would like the user to be able to tap the map and have it expand full screen. Then within the full screen the user can move around and zoom in and out. They will eventually be able to see where I have pins placed based on other users' city where they are located.
I am getting an error when the map is tapped.
Thread 1: "-[HomeTableViewController triggerTouchAction:]: unrecognized selector sent to instance 0x115e2f8a0"
Here is the important code for the map and touch gesture for the controller:
import UIKit
import CoreLocation
import MapKit
class HomeTableViewController: UITableViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
let gestureRecognizer = UITapGestureRecognizer(target: self, action:"triggerTouchAction:")
mapView.addGestureRecognizer(gestureRecognizer)
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 7
}
func triggerTouchAction(gestureReconizer: UITapGestureRecognizer) {
//Add alert to show it works
print("Map Tapped")
}
}
I would love to be able to move forward with this part of my app. Thank you in advance for helping me out. I am very new to coding and wish I had gotten my degree in it.
I think error stems from elsewhere, not AppDelegate.
So, in a viewcontroller type file (class homepage) I want to fetch info from firebase and display. After finishing that section of code, App delegate gives an error.
I've removed the UITableViewDataSource from AppDelegate, then it runs, but doesn't display Firebase info.
class homepage: UITableViewController, CLLocationManagerDelegate{
var people = [Userx]()
#IBOutlet weak var table: UITableView!
public override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return people.count
}
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
as! ViewControllerTableViewCell
let person: Userx = people[indexPath.row]
cell.lblName.text = person.Education
cell.lblgenre.text = person.WhatIamConsideringBuying
return cell
}
var locationManager = CLLocationManager()
override func viewDidLoad() {
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .plain, target: self, action: #selector(signOut))
super.viewDidLoad()
let databaseRef = Database.database().reference()
databaseRef.child("Education").observe(DataEventType.value, with: {snapshot in
if snapshot.childrenCount>0{
self.people.removeAll()
for people in snapshot.children.allObjects as! [DataSnapshot] {
let peopleObject = people.value as? [String: AnyObject]
let peopleEducation = peopleObject?["Education"]
let peopleWhatIamConsideringBuying = peopleObject?["WhatIamConsideringBuying"]
let peoplePhotoPosts = peopleObject?["PhotoPosts"]
let people = Userx(Education: peopleEducation as! String?, WhatIamConsideringBuying: peopleWhatIamConsideringBuying as! String?, PhotoPosts: peoplePhotoPosts as AnyObject)
self.people.append(people)
}
self.table.reloadData()
}
})
///this is different file code for class ViewControllerTableViewCell
class ViewControllerTableViewCell: UITableViewCell {
#IBOutlet weak var lblName: UILabel!
#IBOutlet weak var lblgenre: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Since the error may be in storyboard, the path of homepage is:Homepage Scene - Homepage - Table - Cell - Content View - label 1 and label 2. DataSource and Delegate from Table is connected to Homepage via Outlets.
I just want the error in AppDelegate to disappear so that data can be fetched from firebase.
Here is App Delegate code:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UITableViewDelegate, UITableViewDataSource {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
Database Structure: https://imgur.com/a/CLknEWu
Write this code in your viewDidLoad() method
table.dataSource = self
table.delegate = self
And update your code in cellForRowAt
public override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
if let person = people[indexPath.row] {
cell.lblName.text = person.Education
cell.lblgenre.text = person.WhatIamConsideringBuying
}
return cell
}
To Prevent App from crash
override func viewDidLoad() {
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Sign Out", style: .plain, target: self, action: #selector(signOut))
super.viewDidLoad()
let databaseRef = Database.database().reference()
databaseRef.child("Education").observe(DataEventType.value, with: {snapshot in
if snapshot.childrenCount>0{
self.people.removeAll()
for people in snapshot.children.allObjects as! [DataSnapshot] {
let peopleObject = people.value as? [String: AnyObject]
let peopleEducation = peopleObject?["Education"]
let peopleWhatIamConsideringBuying = peopleObject?["WhatIamConsideringBuying"]
let peoplePhotoPosts = peopleObject?["PhotoPosts"]
if let peopleEducation = peopleEducation as? String {
if let whatIAmConsideringBuying = peopleWhatIamConsideringBuying as? String? {
if let photoPosts = photoPost as? AnyObject {
let people = Userx(Education: peopleEducation, WhatIamConsideringBuying: whatIAmConsideringBuying, PhotoPosts: photoPosts)
self.people.append(people)
}
}
}
}
self.table.reloadData()
}
})
I have a tableView with a textField within row 0 and textView within row 3. My tableview currently slides up every time when the keyboard is present. When the tableView slides up, you can't see the textField within row 0. How do I disable this for row 0 and just keep for row 3? I tried using using Protocol & Delegates to try to encapsulate the function only for row 3, but that doesn't work.
class CreateEditItemController: UIViewController, CreateItemDescriptionCellDelegate {
#IBOutlet weak var tableView: UITableView!
func handleKeyboardShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
//self.view.frame.origin.y -= keyboardSize.height
self.view.frame.origin.y -= 200
}
}
}
func handleKeyboardHide(notification: NSNotification) {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.row {
...
case 3:
let cell = tableView.dequeueReusableCell(withIdentifier: "CreateItemDescriptionCell", for: indexPath) as! CreateItemDescriptionCell
cell.delegate = self
return cell
default:
return tableView.cellForRow(at: indexPath)!
}
}
}
protocol CreateItemDescriptionCellDelegate: class {
func handleKeyboardShow(notification: NSNotification)
func handleKeyboardHide(notification: NSNotification)
}
class CreateItemDescriptionCell: UITableViewCell, UITextViewDelegate {
//IBOUTLETS
#IBOutlet weak var notesTextView: UITextView!
weak var delegate: CreateItemDescriptionCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
notesTextView.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handleKeyboardHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
#objc func handleKeyboardShow(notification: NSNotification) {
delegate?.handleKeyboardShow(notification: notification)
}
#objc func handleKeyboardHide(notification: NSNotification) {
delegate?.handleKeyboardHide(notification: notification)
}
}
What you are trying to do is possible after some mathematics but i would recommend using a third party pod for this instead of doing this manually on evert controller.
Add this to your pod file:
# IQKeyboardManager: Codeless drop-in universal library allows to prevent issues of keyboard sliding up
# https://github.com/hackiftekhar/IQKeyboardManager
pod 'IQKeyboardManagerSwift'
For further detail and documentation view:
https://github.com/hackiftekhar/IQKeyboardManager
The only line you would have to write would be :
// Enabling IQKeyboardManager
IQKeyboardManager.shared.enable = true
in
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
This will solve all your problems and you wont have to calculate the frames or anything.
There are a few routes you can go down, but for simplicities sake, there are a few libraries you can use to get all the calculations down for you and you don't need to worry about it.
One I use all the time is:
TPKeyboardAvoiding - https://github.com/michaeltyson/TPKeyboardAvoiding
IQKeyboardManagerSwift - https://github.com/hackiftekhar/IQKeyboardManager
And many others.
I'm new to IOS developtment but I'm programming an app where the user selects a row from a tableView (view 1). The text that the user selected is then displayed in a label on the same screen. When the user pushes the button the text from the label is stored in UserDefaults and the view changes to view 2. Here I have the viewDidAppear() method that gets the String out of the UserDefaults and changes the text of another Label on view 2.
Here is the code for view 1. The function that is called when the button is clicked is called schoolChosenClicked():
import UIKit
class ChooseSchool: UIViewController, UITableViewDataSource, UITableViewDelegate {
var SchoolNames = [String]()
#IBOutlet weak var table: UITableView!
var refresher: UIRefreshControl!
#IBOutlet weak var LabelSchoolName: UILabel!
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return SchoolNames.count
}
//Set the context
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = SchoolNames[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
LabelSchoolName.text = SchoolNames[indexPath.row]
}
override func viewDidLoad() {
super.viewDidLoad()
SchoolNames.append("Item")
SchoolNames.append("Item")
SchoolNames.append("Item")
SchoolNames.append("")
self.table.register(UITableViewCell.self, forCellReuseIdentifier: "cell");
self.table.dataSource = self
self.table.delegate = self
self.table.reloadData()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func schoolChosenClicked(_ sender: Any) {
UserDefaults.standard.set(LabelSchoolName.text, forKey: "chosenSchool")
}
}
Here is a picture of view 1
Here is the code for view 2
import UIKit
class Login: UIViewController {
#IBOutlet weak var LabelWelcome: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
if var schoolname = UserDefaults.standard.object(forKey: "chosenSchool") as? String
{
print("Das ist der Schoolname:" + schoolname+".")
LabelWelcome.text = "Willkommen bei deiner \(schoolname) App"
}
}
}
And here is the picture of the second view
In the 2nd picture you can see the Label that says "Name Anmelden". This text actually has to change to "Willkommen bei deiner (schoolname) App" but it does't or after a long period of time.
The value schoolname is well present and the print statement works fine but the LabelWelcome.text =... doesn't work or takes a long time. If I try to set the text in the viewDidLoad() method it works fine.
Do you know why or is there a method that i can call to update the screen?
Thank you,
Manuel
PS: Here is the screenshot of my login class (view 2)
Here is the first screenshot of my ChooseSchool class (view 1)
Here is the second screenshot of my ChooseSchool class (view 1
You need to select table cell or need to add text when clicking on the button:
#IBAction func schoolChosenClicked(_ sender: Any) {
LabelSchoolName.text = SchoolNames[indexPath.row]
UserDefaults.standard.set(LabelSchoolName.text, forKey: "chosenSchool")
}
After that still you getting the problem then add synchronize like this when you add your text in userdefault(This is not recommended):
UserDefaults.standard.set(LabelSchoolName.text, forKey: "chosenSchool")
UserDefaults.standard.synchronize()