issue of reuse collection view cell - ios

I have stuck on this issue for 2 days. I don't know why.
I have a collection view for shopping cart purpose. there is a stepper on the reusable cell with a valueChanged event.
I use the following code to handle the problem:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! CartCollectionViewCell
cell.name?.text = cart[indexPath.row].value[0]
let url = URL(string: (baseUrl + (cart[indexPath.row].value[1])))
cell.img.setImageWith(url!)
cell.price?.text = "$" + (cart[indexPath.row].value[2])
cell.remove.addTarget(self, action: #selector(cartViewController.remove_from_cart(sender:)), for: .touchDown)
cell.remove.tag = indexPath.row
cell.qty.value = Double(cart[indexPath.row].value[3])!
cell.qty.addTarget(self, action: #selector(cartViewController.stepperValueChanged(stepper:)), for: .valueChanged)
cell.qty.tag = indexPath.row
return cell
}
func stepperValueChanged(stepper: GMStepper) {
let pos = stepper.convert(CGPoint.zero, to: collection)
let indexPath = collection.indexPathForItem(at: pos)!
let cell: CartCollectionViewCell = collection.cellForItem(at: indexPath) as! CartCollectionViewCell
if cell.qty != nil {
let value = String(Int(cell.qty.value))
var item = cart[indexPath.row]
item.value[3] = value
cart[indexPath.row] = item
}
}
func remove_from_cart(sender: UIButton){
let pos = sender.convert(CGPoint.zero, to: collection)
let indexPath = collection.indexPathForItem(at: pos)!
cart.remove(at: indexPath.row)
amount = 0.0
collection.reloadData()
}
after I scroll the collection view following error occurs:
"fatal error: unexpectedly found nil while unwrapping an Optional value"
let cell: CartCollectionViewCell = collection.cellForItem(at: indexPath) as! CartCollectionViewCell
this line is highlighted by Xcode.

Related

Tap Gesture not Working for imageView in tableview cell

I have 6 custom cells in the table view. In that 3 of them have an image view I added tapGesture to imageView and enabled the user interaction of imageView still not working. I also tried to add tapGesture in main tread in table view cell class but no use, I even tried to add gesture in the cell for at IndexPath method but not worked, how to solve this?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellArr = sections[indexPath.section].cell
//Loading cell based on array details
switch cellArr[0] {
case is InsuranceDetails:
let insuranceCell = tableView.dequeueReusableCell(withIdentifier: "insuranceCell") as! InsuranceCell
insuranceCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
case is Pollution:
let pollutionCell = tableView.dequeueReusableCell(withIdentifier: "pollutionCell") as! PollutionCell
pollutionCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
return pollutionCell
case is Servicing:
let servicingCell = tableView.dequeueReusableCell(withIdentifier: "servicingCell") as! ServicingCell
servicingCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
return servicingCell
case is ChallanPaid:
let challanPaidCell = tableView.dequeueReusableCell(withIdentifier: "challanPaidCell") as! ChallanPaidCell
challanPaidCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
return challanPaidCell
case is InsuranceClaims:
let insuranceClaimCell = tableView.dequeueReusableCell(withIdentifier: "insuranceClaimCell") as! InsuranceClaimCell
insuranceClaimCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
return insuranceClaimCell
case is FuelRefills:
let fuelRefillCell = tableView.dequeueReusableCell(withIdentifier: "fuelRefillCell") as! FuelRefillCell
fuelRefillCell.setup(object: cellArr[indexPath.row], in: tableView, at: indexPath)
return fuelRefillCell
default:
return UITableViewCell()
}
}
one of my tableview cell class
class InsuranceCell: UITableViewCell {
#IBOutlet weak var insurancePhoto: UIImageView!
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
}
func setup(object: NSManagedObject, in table: UITableView, at indexPath: IndexPath) {
guard let arr = object as? InsuranceDetails else {return}
let tapgesture = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
insurancePhoto.isUserInteractionEnabled = true
tapgesture.numberOfTapsRequired = 1
insurancePhoto.isUserInteractionEnabled = true
insurancePhoto.addGestureRecognizer(tapgesture)
// Do time consuming stuff in the background
DispatchQueue.global(qos: .userInitiated).async {
let imageData = arr.insurancePhoto ?? Data()
let image = UIImage(data: imageData)
let compimage = image?.resized(withPercentage: 0.5)
// Always back to the main thread/queue for UI updates
DispatchQueue.main.async {
guard let cell = table.cellForRow(at: indexPath) as? InsuranceCell else { return }
cell.insurancePhoto.image = compimage
}
}
}
}

addTarget to button action within nib of collection view

I have a keyboard extension in iOS 11 that includes a collection view of articles coming in from JSON. I have a button in the prototype cell that I would like to allow a user to press to open the article in Safari external to the keyboard. I can get it to open all links in a static URL, but I cant get it to open each article's URL. What am I missing?
I've put an example of the working simple static action and also included what I have tried but doesn't work in this code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(collectionView == self.key.colImages)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gifCollectionViewCell", for: indexPath) as! gifCollectionViewCell
cell.lblTitle.text = self.articles[indexPath.row].headline
let prefix: String = "https://res.cloudinary.com/djvbbwrnm/image/fetch/"
let options: String = "w_0.2/"
if let imageURL = self.articles[indexPath.row].imageURL
{
let articleURL = self.articles[indexPath.row].url
let url = URL(string: articleURL!)
let urlAppended = prefix+options+imageURL
cell.imgView.sd_setImage(with: URL(string: urlAppended), completed: nil)
//This works
cell.shareButton.addTarget(self, action: #selector(openLink), for: .touchUpInside)
//This doesn't
cell.shareButton.addTarget(self, action: #selector(openUrl(url: url)), for: .touchUpInside)
}
return cell
}
else
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "catCollectionViewCell", for: indexPath) as! catCollectionViewCell
cell.imgView.image = buttPics[indexPath.row]
cell.imgView.layer.cornerRadius = 2
cell.imgView.layer.masksToBounds = true
return cell
}
}
#objc func openLink(){
let articleURL = "http://google.com"
let url = URL(string: articleURL)
openUrl(url: url)
}
#objc func openUrl(url: URL?) {
let selector = sel_registerName("openURL:")
var responder = self as UIResponder?
while let r = responder, !r.responds(to: selector) {
responder = r.next
}
_ = responder?.perform(selector, with: url)
}
You cant add any other DataTypes as arguments. Because, you are adding addTarget for UIButton.
#objc func openLink(){
}
#objc func openLink(sender: UIButton){ // URL is not possible.
}
The above two codes are same. In second one, you can access that UIButton's property.
Runnable Code
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(collectionView == self.key.colImages)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gifCollectionViewCell", for: indexPath) as! gifCollectionViewCell
cell.lblTitle.text = self.articles[indexPath.row].headline
let prefix: String = "https://res.cloudinary.com/djvbbwrnm/image/fetch/"
let options: String = "w_0.2/"
if let imageURL = self.articles[indexPath.row].imageURL
{
//let articleURL = self.articles[indexPath.row].url
//let url = URL(string: articleURL!)
let urlAppended = prefix+options+imageURL
cell.imgView.sd_setImage(with: URL(string: urlAppended), completed: nil)
//This works
cell.shareButton.addTarget(self, action: #selector(openLink), for: .touchUpInside)
//This doesn't
//cell.shareButton.addTarget(self, action: #selector(openUrl(url: url)), for: .touchUpInside)
cell.shareButton.tag = indexPath.row // SET TAG TO UIBUTTON
}
return cell
}
else
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "catCollectionViewCell", for: indexPath) as! catCollectionViewCell
cell.imgView.image = buttPics[indexPath.row]
cell.imgView.layer.cornerRadius = 2
cell.imgView.layer.masksToBounds = true
return cell
}
}
#objc func openLink(sender: UIButton){ // USE THIS.
let buttonTag : Int = sender.tag
let articleURL = self.articles[buttonTag].url
let url = URL(string: articleURL!)
// You can achieve by this way.
// Since I am in a keyboard extension, I added the follwoing code and it is working now.
let selector = sel_registerName("openURL:")
var responder = self as UIResponder?
while let r = responder, !r.responds(to: selector) {
responder = r.next
}
_ = responder?.perform(selector, with: url)
}

How to save index and rating values both?

Here I had used HCSStarRatingview for rating and here i had implemented it in table view so that i need to get the selected particular rating value and need to save according to its index and there should be also in need to change the saved value later also and need to insert in the selected index can anyone help me how to implement this ?
Here is my code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "ratingCell", for: indexPath) as! ratingCell
return cell
}
else if indexPath.section == 1 {
let cell = tableView.dequeueReusableCell(withIdentifier: "reviewCell", for: indexPath) as! AddaReviewTableViewCell
let arr = reviewModel[indexPath.row]
cell.reviewTypeLabel.text = arr.ratingCode
cell.starRatingControl.tag = indexPath.row
cell.starRatingControl.addTarget(self, action: #selector(RatingControlAction(_:)), for: .touchUpInside)
return cell
}
else{
let cell = tableView.dequeueReusableCell(withIdentifier: "reviewInputCell", for: indexPath) as! reviewInputCell
nickName = cell.nameTextField.text
summary = cell.summaryTextField.text
review = cell.reviewTextView.text
cell.submitReviewButton.addTarget(self, action: #selector(submitReviewAction(_:)), for: .touchUpInside)
return cell
}
}
func isValidFirstname(testStr:String) -> Bool {
let firstnameRegEx = "^[a-zA-Z]+$"
let firstnameTest = NSPredicate(format:"SELF MATCHES %#", firstnameRegEx)
let result = firstnameTest.evaluate(with: testStr)
return result
}
func RatingControlAction(_ sender:Any){
let buttonPosition = (sender as AnyObject).convert(CGPoint(), to: tableDetails)
let index = tableDetails.indexPathForRow(at: buttonPosition)
print(String(format: "Changed rating to %.1f", (sender as AnyObject as! CVarArg)))
}
And screenshot for this is shown here
Why don't you create a struct which can hold two values
Declare a struct
struct Struct_Row_Rating {
var row: String
var rating: Int
init(row: String , rating: Int ) {
self.row = row
self.rating = rating
}}
Declare an array
var arrayAdaptor = [Struct_Row_Rating]()
Append array like this
arrayAdaptor.append(Struct_Row_Rating(row: IndexPath.row, rating: 3)
You can retrieve the value by
var index1 = arrayAdaptor[1].rating // use dynamic value here
More on struct

Accessing indexPath in a collectionview

I have a collectionview cell which has an image on it and a button below it. Now when I click on this button, I want to load a tableviewCell which has on it the image from the collectionview. To achieve this, I did this initially..
func SellBtnTapped(_ sender: UIButton) {
let indexPath = collectionView?.indexPath(for: ((sender.superview?.superview) as! RecipeCollectionViewCell))
self.photoThumbnail.image = self.arrayOfURLImages[(indexPath?.row)!]
and photoThumbnail is defined like so...var photoThumbnail: UIImageView! But doing this gives a crash telling 'Unexpectedly found nil while unwrapping an optional value' So I tried this..
let point = sender.convert(CGPoint.zero, to: self.collectionView)
let myIndexPath = self.collectionView.indexPathForItem(at: point)
self.photoThumbnail.image = self.arrayOfURLImages[(myIndexPath?.row)!]
But again, the same crash of Unexpectedly found nil.... is happening. Any idea as to what could be the issue..?
EDIT:
This is the code for cellForItemAtIndex...
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath as IndexPath) as! RecipeCollectionViewCell
cell.sellButton.tag = indexPath.item
cell.sellButton.addTarget(self,action: #selector(SellBtnTapped(_:)),for: .touchUpInside)
return cell
}
It's because you alway get nil your indexPath.
Another approach is
in collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath method
set tag of your cell's button like
cell.myButton.tag = indexPath.item
And in SellBtnTapped method use below code for get indexPath
let indexPath = NSIndexPath(item: sender.tag, section: 0) // set section as you want
let cell = collectionView.cellForItem(at: indexPath as NSIndexPath) as! RecipeCollectionViewCell
Now by use of cell you can get image object that is on it or use self.arrayOfURLImages to get right image. and do your further stuff.
I prefer avoiding tags altogether. I wrote this a while ago and still find it useful.
extension UIView {
var superCollectionViewCell: UICollectionViewCell? {
if let cell = self as? UICollectionViewCell {
return cell
} else {
return superview?.superCollectionViewCell
}
}
var superCollectionView: UICollectionView? {
if let collectionView = self as? UICollectionView {
return collectionView
} else {
return superview?.superCollectionView
}
}
var indexPathOfSuperCollectionViewCell: IndexPath? {
guard let cell = superCollectionViewCell, let collectionView = superCollectionView else { return nil }
return collectionView.indexPath(for: cell)
}
}
This turns your action into
func SellBtnTapped(_ sender: UIButton) {
guard let indexPath = sender.indexPathOfSuperCollectionViewCell else {
print("button has no index path")
return
}
self.photoThumbnail.image = self.arrayOfURLImages[indexPath.row]
}

Value comes as optional("myvalue"), how to get only value without the optional [duplicate]

This question already has answers here:
What is an optional value in Swift?
(15 answers)
Closed 5 years ago.
I am getting my value as Value comes as optional("myvalue"),But how can i get only value without the optional. I have tried a lot but not getting point, any help will be appreciated highly. The thing is that i am using Firebase as database and getting values in database.
I want to get value of Gender, Blood and country code.
Firebase connectivity
ref.child("user_registration").child(UserID!).setValue(["username": fullName.text!, "email": emailTextField.text!, "contact": numberText.text!, "city": myCity.text!, "state":countryText.text!, "gender": genderGroup, "blood": bloodGroup,"code": countryGroup])
Other code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == tableViewB {
let cell = tableViewB.dequeueReusableCell(withIdentifier: "blood", for: indexPath)
cell.textLabel!.text = dropDownList[indexPath.row]
return cell
}
else if tableView == genderT {
let cell = genderT.dequeueReusableCell(withIdentifier: "gender", for: indexPath)
cell.textLabel!.text = genderL[indexPath.row]
return cell
}
else {
let cell = countryT.dequeueReusableCell(withIdentifier: "country", for: indexPath) as! CountryTableViewCell
cell.countryLabel.text = countryL[indexPath.row]
cell.flagImage.image = countryFlags[indexPath.row]
return cell
}
}
var bloodGroup : String?
var genderGroup : String?
var countryGroup : String?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView == tableViewB {
let selectedData = dropDownList[indexPath.row]
buttonB.setTitle(selectedData, for: .normal)
self.tableViewB.isHidden = true
self.flag = 1
let indexPath = tableViewB.indexPathForSelectedRow
let currentCell = tableViewB.cellForRow(at: indexPath!)! as UITableViewCell
bloodGroup = currentCell.textLabel!.text!
print("\(bloodGroup)")
}
else if tableView == genderT {
let selectedDataG = genderL[indexPath.row]
genderB.setTitle(selectedDataG, for: .normal)
self.genderT.isHidden = true
self.flag = 1
let indexPath = genderT.indexPathForSelectedRow
let currentCell = genderT.cellForRow(at: indexPath!)! as UITableViewCell
genderGroup = currentCell.textLabel!.text!
print("\(genderGroup)")
}
else {
let selectedDataG = countryL[indexPath.row]
countryB.setTitle(selectedDataG, for: .normal)
self.countryT.isHidden = true
self.flag = 1
let indexPath = countryT.indexPathForSelectedRow
let currentCell = countryT.cellForRow(at: indexPath!)! as! CountryTableViewCell
countryGroup = currentCell.countryLabel.text!
let finalFlag = currentCell.flagImage.image!
print("\(finalFlag)" + "\(countryGroup)")
}
}
<br>
Console
com.apple.MobileAsset.TextInput.SpellChecker
Optional("male")
Optional("A+")
<UIImage: 0x600000295950>, {96, 64}Optional("+92")
fatal error: unexpectedly found nil while unwrapping an Optional value
Try this :
Print object
print(bloodGroup ?? "")
And
cell.textLabel!.text = (dropDownList[indexPath.row] ?? "")
Please write
if tableView == tableViewB {
let cell = tableViewB.dequeueReusableCell(withIdentifier: "blood", for: indexPath)
cell.textLabel!.text = dropDownList[indexPath.row] as! String
return cell
}
Instead of
if tableView == tableViewB {
let cell = tableViewB.dequeueReusableCell(withIdentifier: "blood", for: indexPath)
cell.textLabel!.text = dropDownList[indexPath.row]
return cell
}
In table view cellForRowAt method.

Resources