I am using limit option in tablview using swift.
for example:
If limit value contain "2" only two checkbox will able to select remaining checkbox will not able to select and
If limit value contain "0" all checkbox will able to select
The issue is you are trying to assign nil values to something.You are using ! in your code. It is hard unwrapping.If you use this mark 100% make sure your value is there.If you not sure use optional unwrapping.
Not Use,
let cell: MultiOnlinecell = self.onlinediscountmultiarraytableview.cellForRow(at: index) as! MultiOnlinecell
Use this, It is save you from app crash
let cell: MultiOnlinecell = self.onlinediscountmultiarraytableview.cellForRow(at: index) as? MultiOnlinecell ?? UITableViewCell()
Related
Language : Swift , REALM, Working with tableview cells to display user entries.
I have a problem where I cannot figure out how to display images in a table view cell where each cell has different number of images coming in and the images itself are optional when the user saves their entry.
here is my problem - When I create a new image view in my stack view as you see in the code, to display the second image in the list, I am getting the error that the index path is out of bounds. Also, I cannot unwrap the journalAspects.inPictures[0].realmToThumbNailImage() because I get an error saying that it is not optional.
How do I go about solving this problem of showing different number of images in different cells with out crashing the app.
I have 3 user entries in my app
1st one has text, date and no images
2nd one has text, date and 1 image
3rd one has text, date and 2 images
here is what I want to see in my table view cell
first cell with just text and date
second cell with text, date and 1 image
third cell with text, date and 2 images
Thank you very much and your input is highly appreciated.
here is my code :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let displayCell = journalAspectTableViewDispay.dequeueReusableCell(withIdentifier: "firstAddCell", for: indexPath) as! FirstAddTableViewCell
if let journalAspects = RealmEntries?[indexPath.row] {
//MARK: Text display
displayCell.journalTextDisplayLabel.text = journalAspects.realmText
let pictureImageView = UIImageView()
pictureImageView.heightAnchor.constraint(equalToConstant: 70).isActive = true
pictureImageView.widthAnchor.constraint(equalToConstant: 70).isActive = truedisplayCell.stackViewForImageShow.addArrangedSubview(pictureImageView)
let secondpictureImageView = UIImageView()
secondpictureImageView.heightAnchor.constraint(equalToConstant: 70).isActive = true
secondpictureImageView.widthAnchor.constraint(equalToConstant: 70).isActive = true
displayCell.stackViewForImageShow.addArrangedSubview(secondpictureImageView)
if journalAspects.inPictures.count == 0 {
return displayCell
} else {
let imagesComingOut = journalAspects.inPictures[0].realmToThumbNailImage()
secondpictureImageView.image = imagesComingOut
let secondimagesComingOut = journalAspects.inPictures[1].realmToThumbNailImage() -- App crashes
pictureImageView.image = secondimagesComingOut -- App crashes
}
}
return displayCell
}
Hi, Thank you for your feedback, It is working, But when I implement it, I am having a strange problem. As I add new entries, the number of rows in the section won't change, and weird things happen. At first as I run and compile the app from the Xcode, everything seems right. Entries with one image has one image, entries with no image has no image and entries with 2 has 2. But as I scroll up and down, suddenly entries with no image gets populated with some image. Even though, I have added a new entry, the number of rows will still return the same. For instance if I have 10 entries at the start by running the compiler on the Xcode, then I add the 11th entry, as I scroll, the table view adds the 11th entry as 10th and knocks out the first entry. No matter how many I add, they just knock one down and add another at the top making the number of rows I see as a constant number since it is compiled. If you have any idea as to why that is happening, Please let me know Thank you again.
Have you checked that inPictures actually contains 2 images? You check that there's greater than 0, but not > 1. That can be the only reason for an out of range error in that line. A safer way would be:
switch journalAspects.inPictures.count {
case 2:
secondpictureImageView.image = journalAspects.inPictures[0].realmToThumbNailImage()
pictureImageView.image = journalAspects.inPictures[1].realmToThumbNailImage()
case 1:
pictureImageView.image = journalAspects.inPictures[1].realmToThumbNailImage()
// or maybe the other one - hard to tell as you've mixed up sequencing
default: break
}
return displayCell
I'm working on a spendings tracker app. All the logic is now working, but when I want to display transaction data in a UILable, it displays it as optional("String")
I have looked around the Internet and have tried unwrapping the string in 2 different ways, but I'm not able to fix it.
Adding an ! to the end of the string gives an error Cannot force unwrap value of non-optional type "String"
Here is the code I'm using now that displays optional("String")
Here I set up my struct and array
struct Transaction {
var discr = ""
var amount = 0
}
var transactions = [Transaction]()
This is how I add data to the array
transactions.append(Transaction( discr: String(describing: transDescrInput.text), amount: Int(tempAmount)))
This is how I display the data in a tableview
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = transTable.dequeueReusableCell(withIdentifier: "sCell")
let discrText = transactions[indexPath.row].discr.uppercased()
cell?.textLabel?.text = "€\(transactions[indexPath.row].amount)"
cell?.detailTextLabel?.text = "\(discrText)"
return cell!
}
This is how it shows up in the app
Iphone simulator screenshot
The problem is already where you add data to the array.
Assuming that transDescrInput.text is an optional string,
String(describing: transDescrInput.text)
returns a non-optional string "Optional(text...)" and there is
no sensible way to revert that. You should use optional binding
or other unwrapping mechanisms instead, for example
if let text = transDescrInput.text {
transactions.append(Transaction(discr: text, amount: Int(tempAmount)))
}
or with nil-coalescing:
transactions.append(Transaction(discr: transDescrInput.text ?? "", amount: Int(tempAmount)))
As a rule of thumb, String(describing:) almost never the correct
solution (even if the compiler suggest it as a Fix-it), it only hides
the actual problem.
Right after posting this post I realised I have to unwrap the text before I add it to my array. So I changed the way I save the string:
transactions.append(Transaction( discr: String(describing: transDescrInput.text!), amount: Int(tempAmount)))
I added an ! behind the transDescrInput.text to unwrap it before I save it to my array.
May I suggest do something like this?
let discrText = transactions[indexPath.row].discr.uppercased()
cell?.detailTextLabel?.text = "\(discrText!)"
This is more for interest rather than a problem, but I have an NSMutableSet, retrieved from UserDefaults and my objective is to append an item to it and then write it back. I am using an NSMutableSet because I only want unique items to be inserted.
The type of object to be inserted is a custom class, I have overrode hashCode and isEqual.
var stopSet: NSMutableSet = []
if let ud = UserDefaults.standard.object(forKey: "favStops") as? Data {
stopSet = NSKeyedUnarchiver.unarchiveObject(with: ud) as! NSMutableSet
}
stopSet.add(self.theStop!)
let outData = NSKeyedArchiver.archivedData(withRootObject: stopSet)
UserDefaults.standard.set(outData, forKey: "favStops")
NSLog("Saved to UserDefaults")
I get the set, call mySet.add(obj) and then write the set back to UserDefaults. Everything seems to work fine and (as far as I can see) there don't appear to be duplicates.
However is it possible to tell whether a call to mySet.add(obj) actually caused an item to be written to the set. mySet.add(obj) doesn't have a return value and if you use Playgrounds (rather than a project) you get in the output on the right hand side an indication of whether the set was actually changed based on the method call.
I know sets are not meant to store duplicate objects so in theory I should just trust that, but I was just wondering if the set did return a response that you could access - as opposed to just getting the length before the insert and after if I really wanted to know!
Swift has its own native type, Set, so you should use it instead of NSMutableSet.
Set's insert method actually returns a Bool indicating whether the insertion succeeded or not, which you can see in the function signature:
mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element)
The following test code showcases this behaviour:
var set = Set<Int>()
let (inserted, element) = set.insert(0)
let (again, newElement) = set.insert(0)
print(inserted,element) //true, 0
print(again,oldElement) //false,0
The second value of the tuple returns the newly inserted element in case the insertion succeeded and the oldElement otherwise. oldElement is not necessarily equal in every aspect to the element you tried to insert. (since for custom types you might define the isEqual method in a way that doesn't compare each property of the type).
You don't need to handle the return value of the insert function, there is no compiler warning if you just write insert like this:
set.insert(1)
I have noticed when I code in Swift I routinely get an auto correct from the compiler when I use optionals and I am trying to understand the meaning behind this. When I have a variable that is optional and I try to use without unwrapping it, I often get a (?)! autocorrection from Xcode.
In my code I have an optional property that will be the data source collection for my UITableView:
var procedures: [Procedure]?
First I will try to use it like so:
The compiler is telling me that I need to use the ? syntax suffix for my self.procedures.
So I click on the little red circle and have it autocorrect for me like so:
But now the compiler is still complaining. About what you ask? Well, it apparently wants self.procedures?.[indexPath.row] to be enclosed in parenthesis with the ! bang operator at the end...
So I click the little red circle again and have it auto correct like so:
Now the compiler is happy, but I am not. Why am I not happy you ask? Because I do not understand what the () parenthesis are doing here.
Could someone please explain?
So as you can see, you are declaring your procedures as an optional
var procedures: [Procedure]?
then you are trying to pass it to a function that will accept Procedure
cell.configureWithProcedure(procedure: Procedure)
Then you are trying to access your procedure with index like this
self.procedures[indexpath.row]
That will result an error because self.procedures is an optional, so you need to unwrap it, then you try to add ?
self.procedures?[indexpath.row]
This will solve the problem, but the result of it won't be a normal Procedure but an Optional Procedure -> Procedure?.
So XCode give you a hint to unwrap it because your configureWithProcedure ask for Procedure not Procedure? in one line that will be writen like this
(self.procedures?[indexPath.row])!
This operation will result unwrapped Procedure, but I don't recommend you to use the ! operator because it's dangerous, so I recommend you to do like this
if let procedure = self.procedures?[indexPath.row] {
cell.configureWithProcedure(procedure: procedure)
}
EDIT :
in your case you can return an empty cell if procedure isn't exist
extension UITableViewCell {
dynamic class func emptyCell() -> UITableViewCell {
let cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: nil)
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
}
and write it like this
if let procedure = self.procedures?[indexPath.row] {
cell.configureWithProcedure(procedure: procedure)
} else {
return UITableView.emptyCell()
}
or even better use guard
guard let procedure = self.procedures?[indexPath.row] else {
return UITableView.emptyCell()
}
cell.configureWithProcedure(procedure: procedure)
Hope my answer can help you!
Heys guys,
I am pretty new into programming and therefore I've followed I course on Udemy to teach me Swift 2.2.
For learning purpose I have been trying to program a BMI-calculator where I have a textfield (which just displays the value) and a slider where I can put my weight in kg. After dragging the slider the value is visible in the textfield. I cannot put a value into the textfield so that it is displayed on the slider!
The same textfield-slider relation is used with the height in cm. Now I created an IBAction the bring my kgSlider.value into my kgField.text and it looks like this:
#IBAction func kgSet(sender: AnyObject) {
kgField.text! = String(Int(kgSlider.value))
}
Thats works fine but I unwrapped (like the teacher in the course) without knowing, if there really is a value. Okay, I know in this case that there will be a value, but I would like to go more real and therefore I tried to use an Optional-Binding to find out, if there is a value instead of directly unwrap it.
Therefore I used the cm.Field and the cm.Slider in my code but it doesn't work for now and I don't know why. The code is the following:
#IBAction func cmSet(sender: AnyObject) {
if let tempCm = String(Int(cmSlider.value)) as String! {
cmField.text = tempCm
}
}
So I created the constant called tempCM which will got the value from the cmSlider, if there is a value. Therefore I casted the cmSlider.value like in the other IBAction into an Int and then into a String. If there is the value it will carry it into the cmField.text. This didn't work, therefore I tried to use the "as String!" statement but know I get always 0 instead of the correct value.
So what am I doing wrong there?
So, this should compile fine and provide you with your desired result.
#IBAction func cmSet(sender: AnyObject) {
if let tempCm = String(Int(cmSlider.value)) {
cmField.text = tempCm
}
}
You could also try this
cmField.text = String(Int(cmSlider.value)) ?? " "
in the second example, you are using the optional operator to say if you can convert this to an Int then that Int to a string set the cmField.text property to its value, otherwise use a blank space as the default value.