Writing a conditional statement for empty UITableView - ios

The following function below is displaying an alert if no selections are made in UITableView.
But I do not want the alert to come up when the TableView has no records. How can this be done?
Work so far:
#IBAction func onTapNextButton(_ sender: UIBarButtonItem) {
guard let selectedIndexPaths = tableView.indexPathsForSelectedRows, !selectedIndexPaths.isEmpty else {
//Show Alert here...
let alert = UIAlertController(title: "Alert..!!", message: "You must select atleast 1 row before proceeding.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
return
}
}

First check if the data source array is not empty, replace dataSourceArray with the real name
guard !dataSourceArray.isEmpty else { return }
guard let selectedIndexPaths = tableView.indexPathsForSelectedRows,
!selectedIndexPaths.isEmpty else {
let alert ...

Whatever the object is that you're using as your data source (I'm assuming it's an array), check to see if that object (array) has zero elements. So, for example, something like:
//tableViewData should be the name of the array you're using as your data source
if tableViewData.isEmpty {
return
}
That way if there are no rows, you exit the function, and it won't display the alert.

// this is one way of checking if the tableView is empty
#IBAction func onTapNextButton(_ sender: UIBarButtonItem) {
if tableView.visibleCells.isEmpty {
//table view is empty: do something
} else {
guard let selectedIndexPaths = tableView.indexPathsForSelectedRows, !selectedIndexPaths.isEmpty else {
//Show Alert here...
let alert = UIAlertController(title: "Alert..!!", message: "You must select atleast 1 row before proceeding.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
return
}
}
}
***** Hope you like it *****

Related

Swift 5 - Validation in textfields through UIAlertView

So I'm using Swift 5 and working with core data. I'm trying to add validation to the textfields through the UIAlertView.
To give clarification to what my code already does:
User presses a button which the iOS Photo Library Interface Pops up.
Once photo is selected a UIAlertViewpops up and asks me two enter texts in two textfields.
Once that is done, the data is submitted to the database and displays the image and the texts that I entered onto a TableViewCell
The issue?
When submitting a blank text field, there is no prompt to tell the user to enter texts. It will just display the image only in the UITableViewCell without any texts which is the obvious result when inputting no strings.
What do I want to achieve?
To add a validation message to the user when they enter no text and cancel the process of submitting to the database.
What I've already tried?
Please see below for code. Note: Submitting an image and texts to the database already works, my issue is with textfield validation
func createBrandItem (with image:UIImage){
let brandItem = Brand(context: managedObjectContext)
brandItem.image = NSData(data: image.jpegData(compressionQuality: 0.3)!) as Data
let inputAlert = UIAlertController(title: "New Brand", message: "Enter an item and a brand.", preferredStyle: .alert)
inputAlert.addTextField { (textfield:UITextField) in
textfield.placeholder = "Item"
}
inputAlert.addTextField { (textfield:UITextField) in
textfield.placeholder = "Brand"
}
inputAlert.addAction(UIAlertAction(title: "Save", style: .default, handler: { (action:UIAlertAction) in
let itemTextField = inputAlert.textFields?.first
let productTextField = inputAlert.textFields?.last
if (itemTextField?.text!.isEmpty)! || (productTextField?.text!.isEmpty)! {
let alertBlankInput = UIAlertController(title: "Blank Input", message: "Please don't leave the textfields empty.", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.cancel)
alertBlankInput.addAction(okAction)
self.present(alertBlankInput, animated: true, completion: nil)
}
if itemTextField?.text != "" && productTextField?.text != "" {
brandItem.item = itemTextField?.text
brandItem.brand = productTextField?.text
do{
try self.managedObjectContext.save()
self.loadData()
}
catch{
print("Could not save data \(error.localizedDescription)")
}
}
}))
inputAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
if self.presentedViewController == nil {
self.present(inputAlert, animated: true, completion: nil)
}
else {
self.dismiss(animated: false, completion: nil)
self.present(inputAlert, animated: true, completion: nil)
}
}
Breaking the code down
The snippet below is what I tried adding to the createBrandItem function. When I add this ifstatement when debugging the app, it uses this conditional statement but also completes the conditional statement where it adds to the database.
if (itemTextField?.text!.isEmpty)! || (productTextField?.text!.isEmpty)! {
let alertBlankInput = UIAlertController(title: "Blank Input", message: "Please don't leave the textfields empty.", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.cancel)
alertBlankInput.addAction(okAction)
self.present(alertBlankInput, animated: true, completion: nil)
}
The code below is the snippet which adds the data to the database.
let brandItem = Brand(context: managedObjectContext)
brandItem.image = NSData(data: image.jpegData(compressionQuality: 0.3)!) as Data
if itemTextField?.text != "" && productTextField?.text != "" {
brandItem.item = itemTextField?.text
brandItem.brand = productTextField?.text
do{
try self.managedObjectContext.save()
self.loadData()
}
catch{
print("Could not save data \(error.localizedDescription)")
}
}
Summary
How would I go if the textfields are empty and stops the process of submitting to the database?
I'd recommend creating your own child view controller which you present as a model dialogue, which would be more elegant and give you far greater control over the process flow. However if you want to continue with an alert controller, you could make it work by creating the OK action in a disabled state:
let okAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.cancel)
okActions.isEnabled = false
inputAlert.addAction(okAction)
and then use textFields' delegates to validate the content of the text fields (you'd need to have a means to coordinate between the two textfields - you could use the alertController's textfields? array to cross-check, or use local variables as flags) and when you're happy with the content of both
inputAlert.actions.filter({$0.title == "OK" }).first?.isEnabled = true

Trying to refresh a collection view using alert completion

I have a screen with a collection view, and a plus sign bar button item. When the plus sign is pressed, an alert window pops up, where the user can add information to the list. Upon hitting OK, I am trying to refresh the collection view, but I'm doing something wrong.
The print statement "passed guard" is achieved, and I can get the information they entered. Just can't refresh the view to reflect this without leaving and coming back. Any guidance? I've run into this a few times actually, so I'm clearly missing something. Thanks very much in advance.
#objc func newButtonPressed() {
let alert = UIAlertController(title: "Add", message: "", preferredStyle: .alert)
alert.addTextField { (textField) in
textField.placeholder = "Name"
}
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
var name = ""
guard let textFields = alert.textFields else { return }
guard let navController = self.parent as? UINavigationController else { return }
guard let settingsVC = navController.topViewController as? SettingsVC else { return }
print("passed guard") // success
DispatchQueue.main.async {
settingsVC.collectionView.reloadData()
settingsVC.view.backgroundColor = .red
// For testing purposes, explicitly using main thread and setting to red
}
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alert, animated: true, completion: nil)
}
May be you need to alter the collection dataSource
guard let textFields = alert.textFields else { return }
settingsVC.arr.append(textFields.first!.text!) // arr is collection dataSource
settingsVC.collectionView.reloadData()

How Swift code is excecuted in Xcode

I've got a Problem. I'm new to iOS programming, and i'm struggling to understand how Swift code is excecuted. For example, in the piece of code below, I would think that every line is executed right after the one above. But when it reaches the passData() function, it does not ejecute that fuction. it keeps going, and some time later (or erlier) it excecutes it (the passData function).
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if numLaunches == 0{
nombre = usuario()
numLaunches += 1
}
}
func usuario() -> String {
var tField: UITextField!
func configurationTextField(textField: UITextField!)
{
print("generating the TextField")
textField.placeholder = "Enter an item"
textField.textAlignment = .center
tField = textField
}
func handleCancel(alertView: UIAlertAction!)
{
print("Cancelled !!")
}
let alert = UIAlertController(title: "Please Enter Your Name", message: "", preferredStyle: .alert)
alert.addTextField(configurationHandler: configurationTextField)
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler:handleCancel))
alert.addAction(UIAlertAction(title: "Done", style: .default, handler:{ (UIAlertAction) in
print("Done !!")
print("Item : \(String(describing: tField.text))")
self.nombre = tField.text!
}))
self.present(alert, animated: true, completion: {
print("completion block")
})
print(self.nombre)
passData()
if tField.text == nil {
return "No value"
}else{
return (tField.text!)
}
}
func passData() {
let myVC = storyboard?.instantiateViewController(withIdentifier: "SecondVC") as! AboutViewController
if myVC.playerName != nil {
myVC.playerName.text = nombre
}else{
}
navigationController?.pushViewController(myVC, animated: true)
print("pasa el dato")
}
So, the Problem is, that i need to pass the content of the variable "nombre" to another VC. But when the passData function is excecuted that variable is empty. I thought if i called that function after the variable was updated, it Will pass the right content. But im clearly mistaken.
I would appreciate the help!
In general, unless your functions are asynchronous, you are correct in your understanding that code is executed from top down. In this case I think you are just confused about your UIAlertAction code. It appears you are popping an alert to the user, asking them to write their name, and when they hit "Done" you want to call your passData() function. In that case, you should put that passData() call inside your UIAlertAction, like so:
alert.addAction(UIAlertAction(title: "Done", style: .default, handler:{ (UIAlertAction) in
print("Done !!")
print("Item : \(String(describing: tField.text))")
self.nombre = tField.text!
self.passData()
}))
The code inside the handler for your UIAlertActions will not be executed until the user presses that button, which is why you are finding that passData is getting called too early.

How to disable a UIButton and send a UIAlertView message

I am trying to disable a menu button is the array is shows is empty.
This is my code.
#IBAction func likedmenubuttontouched(sender: AnyObject) {
if Globals.likedArray.isEmpty {
likedMenuButton.userInteractionEnabled = false
let ac = UIAlertController(title: "No liked quotes yet", message: "No liked quotes have been chosen, go explore!", preferredStyle: .Alert)
ac.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
presentViewController(ac, animated: true, completion: nil)
return
} else {
likedMenuButton.userInteractionEnabled = true
}
}
And in ViewDidLoad()
likedMenuButton.userInteractionEnabled = false
I have managed to disable the button, but I want to send a message alerting the user why the button is disabled, otherwise, its a little confusing.
How would I go about doing this?
Thanks.
As by default the the user Interaction is true you need not to make it true
#IBAction func likedmenubuttontouched(sender: AnyObject) {
if Globals.likedArray.isEmpty {
let ac = UIAlertController(title: "No liked quotes yet", message: "No liked quotes have been chosen, go explore!", preferredStyle: .Alert)
ac.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
presentViewController(ac, animated: true, completion: nil)
} else {
//segue to the other view
}
}
Also check your array count, that is why your wrong condition is executing

How to display AlertController in UiView

new to Swift. Below code is executed without error but in the console it shows a message. Is it an error message and how to fix it? Is it required to be fixed when sending app for review.
Thanks
This is my App structure :
VC(1) --> goto --> VC(2)
In VC(1) I have:
BtnGo
UiLabelMsg
UitableView
I created a Link to VC(2) : Control-Drag BtnGo to VC(2)
I named the segue : SegueToVC2
What I wanted to do:
I need to pass a string to VC2. Before passing check if user made a selection.
in PrepareForSegue,
override func PrepareForSegue(segue:UIStoryboardSegue, sender: AnyObject!) {
var strchk: String = UIlabelMsg.text!
if strchk.isEmpty {
var alert = UIAlertController(title: "Alert",message:" No Selection made",
preferredStyle: UIAlertControllerStyle.Alert)
alert.AddAction(UIAlertction(title: "OK",style:UIAlertActionStyle.Default,hanlder: nil))
self.presentViewController(alert, animated: true, completion: nil )
} else {
if (segue.Identifier =="SegueToVC2") {
var targetVC = segue.destinationViewControl as! VC2
targetVC.strMsg = UILabelMsg.text
}
}
Problem:
in the console, it shows this:
UIView : 0x7fdfc25668c0; frame =(0,0,375,667); autoresize = w+h; layer
= 's windows is not equal to 's View's Window!
I have these questions
How come I don't need to write code for BtnGo when I use prepareForSegue?
if I have more than 2 button? these 2 will handle by Segue?
UIView have not presentViewController method, what's the self? You can using window of UIView to presenting.
let alert = UIAlertController(title: "Alert", message: "No Selection made", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.window?.rootViewController?.present(alert, animated: true, completion: nil)
EDIT: Possible you need to override the shouldPerformSegueWithIdentifier to check the UIlabelMsg.text.
override func shouldPerformSegueWithIdentifier(identifier: String?, sender: AnyObject?) -> Bool {
var strchk: String = UIlabelMsg.text!
if strchk.isEmpty {
var alert = UIAlertController(title: "Alert",message:" No Selection made",
preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK",style:UIAlertActionStyle.Default,handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
return false
} else {
return true
}
}

Resources