I'm having issue with completion handler using generic function, it seems that it won't pass anything on the UITableView, unless I will put some break point on it, please check my code below:
public func requestGenericData<T: Decodable>(urlString: String, httpMethod: String?, token: String!, completion: #escaping(T) ->()) {
let fullStringUrl = url + urlString
guard let url = URL(string: fullStringUrl) else { return }
guard let token = token else { return }
var urlRequest = URLRequest(url: url)
urlRequest.setValue("application/json", forHTTPHeaderField: "accept")
urlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
urlRequest.httpMethod = httpMethod
URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if self.isInternetAvailable() {
guard let data = data else { return }
if let httpResponse = response as? HTTPURLResponse {
if httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 {
do {
let obj = try JSONDecoder().decode(T.self, from: data)
completion(obj)
} catch {
print("Error: \(String(describing: error))\n StatusCode: \(httpResponse.statusCode)")
}
}
}
} else {
showAlert(title: "No Internet Connect", message: "Please open your network and try again.", alertStyle: .alert, buttonTitle: "OK", buttonStyle: .default)
return
}
}.resume()
}
and this is the function that will show the list of of it's result in the table view code below:
func listOfServicesMenus() {
var jobsInCategory = [String]()
apiHelper.requestGenericData(urlString: "nothing/more/than/a/noob", httpMethod: "GET", token: token) { (noobs: Noobs) in
for job in jobs.jobCategories {
jobsInCategory.append(job.name)
for jobDetails in job.getJobs {
jobsInCategory.append(jobDetails.name)
}
}
self.listOfServices.dropView.dropDownOptions = jobsInCategory
}
}
New to swift and developing iOS, it seems that when ever I put break point on it seems working fine, how ever when not, it doesn't show anything?
Does anyone any idea on how to implement a proper completion handler with generics or do I missed something on it when try to write this code?
Thanks for those who are helping me out of this.
Update
I created a so called DropDownMenu using UIView, UITableViewDelegate, UITableViewDataSource, UITableView (which is created under the UIView for proper handling of constraints).
Update 2
Added implementation of UITableView(under UIView)
class dropDownView: UIView, UITableViewDelegate, UITableViewDataSource {
var dropDownOptions = [String]()
var tableView = UITableView()
var delegate: DropDownDelegate!
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.backgroundColor = UIColor.clear.cgColor
self.backgroundColor = UIColor.clear
tableView.delegate = self
tableView.dataSource = self
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.layer.cornerRadius = 10
tableView.backgroundColor = UIColor(displayP3Red: 166/255, green: 203/255, blue: 69/255, alpha: 1.0)
self.addSubview(tableView)
tableView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
tableView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let cell = UITableViewCell()
cell.contentView.backgroundColor = UIColor.clear
return dropDownOptions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
cell.textLabel?.text = dropDownOptions[indexPath.row]
cell.textLabel?.textColor = UIColor(displayP3Red: 166/255, green: 203/255, blue: 69/255, alpha: 1.0)
cell.layer.borderColor = UIColor(displayP3Red: 112/255, green: 112/255, blue: 112/255, alpha: 1.0).cgColor
cell.backgroundColor = UIColor(displayP3Red: 254/255, green: 252/255, blue: 215/255, alpha: 1.0)
cell.selectionStyle = .none
cell.textLabel?.textAlignment = .center
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell: UITableViewCell = tableView.cellForRow(at: indexPath)!
selectedCell.contentView.backgroundColor = UIColor(displayP3Red: 133/255, green: 178/255, blue: 56/255, alpha: 1.0)
selectedCell.textLabel?.textColor = UIColor.white
self.delegate.dropDownPressed(string: self.dropDownOptions[indexPath.row])
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cellToDeSelect:UITableViewCell = tableView.cellForRow(at: (indexPath))!
cellToDeSelect.contentView.layer.borderColor = UIColor(displayP3Red: 112/255, green: 112/255, blue: 112/255, alpha: 1.0).cgColor
cellToDeSelect.contentView.backgroundColor = UIColor(displayP3Red: 254/255, green: 252/255, blue: 215/255, alpha: 1.0)
cellToDeSelect.textLabel?.textColor = UIColor(displayP3Red: 166/255, green: 203/255, blue: 69/255, alpha: 1.0)
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.contentView.backgroundColor = UIColor.clear
}
Thanks to you Anil Varghese, created another function that will reload data under the dropDownView class and added this line of code:
func reloadData() {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
Related
Hello I'm trying to do a List that is populated with query results from Firebase Database
I've got constantly some problems and i have no clue what can i try to do next ive looked through internet to help me do this but found nothing, can you help me?
Thanks in Advance
Here is the code with errors
class BoatListViewContoller: UIViewController, UITableViewDelegate, UITableViewDataSource {
var title = [""] // Here error is saying "Property 'title' with type '[String]' cannot override a property with type 'String?'"
var lenght:Int?
func readProducts(){
let db = Firestore.firestore()
db.collection("products").getDocuments(){
querySnapshot, err in
if let err = err {
print("Error getting documents: \(err)")
} else {
self.lenght = querySnapshot!.count
for document in querySnapshot!.documents{
self.title.append(document.data()["title"] as! String) // Here i got a error saying "No exact matches in call to subscript"
}
}
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return lenght!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath as IndexPath)
cell.textLabel!.text = title[indexPath]
cell.backgroundColor = UIColor.init(red: 212/255, green: 255/255, blue: 241/255, alpha: 1)
return cell
}
private var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad();
let displayWidth: CGFloat = self.view.frame.width
let displayHeight: CGFloat = self.view.frame.height
myTableView = UITableView(frame: CGRect(x: 0, y: 0, width: displayWidth, height: displayHeight))
myTableView.register(UITableViewCell.self, forCellReuseIdentifier: "MyCell")
myTableView.dataSource = self
myTableView.delegate = self
myTableView.backgroundColor = UIColor.init(red: 212/255, green: 255/255, blue: 241/255, alpha: 1)
view.addSubview(myTableView)
}
}
First error:
UIViewController already has a property named title:
open var title: String?
You just need to rename var title = [""] to var titles = ["], or something different than title.
Second error:
You might try document.get("title") as! String (borrowed the idea from https://stackoverflow.com/a/54601354/3227743), or you might try
let data = document.data()
let title = data["title"]
or
self.title.append((document.data())["title"] as! String)
Miscellaneous:
You would also need to call myTableView.reloadData() after parsing every document.
Nitpick: length instead of lenght. Also, you actually don't need that since you could (should) just use titles.count instead.
i am implementing collection view as my ChatMessagViewController and i am populating message in collectionview all things works perfect for me but issue is that when i scrolled collection view message was . issing or replaced on scroll let me show you my code for populating collectionview
here i am adding screen shot for what output i get before scrolling and after scrolling please have a look
func loadMessageData(){
self.message.removeAll()
guard let uid = Auth.auth().currentUser?.uid else{
return
}
let userref = Database.database().reference().child("Message").child(uid)
userref.child(self.senderID!).observe(.childAdded, with: { (snapshot) in
print(snapshot)
if let dictonary = snapshot.value as? [String:AnyObject]{
let key = snapshot.key
let mainDict = NSMutableDictionary()
mainDict.setObject(key, forKey: "userid" as NSCopying)
self.namesArray.add(mainDict)
let message = Message(dictionary: dictonary)
self.message.append(message)
self.timer?.invalidate()
self.timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(self.handleReload), userInfo: nil, repeats: false)
}
}, withCancel: nil)
}
extension ChatViewController: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return message.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as! ChatMessageCell
let message1 = message[indexPath.item]
cell.tetxtView.text = message1.msg
cell.bubbleWidthAnchor?.constant = estimatedFrameForText(text: message1.msg!).width + 32
let ketID = message1.key_id
if ketID == Auth.auth().currentUser?.uid{
cell.bubbleView.backgroundColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1)
cell.bubbleViewRightAnchor?.isActive = false
cell.bubbleViewLeftAnchor?.isActive = true
}else{
cell.bubbleView.backgroundColor = UIColor(red: 0/255, green: 158/255, blue: 214/255, alpha: 1)
cell.tetxtView.textColor = UIColor.white
cell.bubbleViewRightAnchor?.isActive = true
cell.bubbleViewLeftAnchor?.isActive = false
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
var height: CGFloat = 80
if let mesg = message[indexPath.item].msg{
height = estimatedFrameForText(text: mesg).height + 20
}
return CGSize(width: view.frame.width, height: height)
}
}
and here is the collectionview methods for populating
issue is that when i scroll the message was replaced or missing
please check screen shot first i am getting messages and after scrolling i came back to top message is missing
cell.tetxtView.textColor is dequeued make sure to add it inside the if also
if ketID == Auth.auth().currentUser?.uid{
cell.bubbleView.backgroundColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1)
cell.tetxtView.textColor = UIColor.black /////// here
cell.bubbleViewRightAnchor?.isActive = false
cell.bubbleViewLeftAnchor?.isActive = true
}else{
cell.bubbleView.backgroundColor = UIColor(red: 0/255, green: 158/255, blue: 214/255, alpha: 1)
cell.tetxtView.textColor = UIColor.white
cell.bubbleViewRightAnchor?.isActive = true
cell.bubbleViewLeftAnchor?.isActive = false
}
The text color is white so it same as the background of it's superview , hence doesn't appear
I am trying to create seatMap and I want to hide the image for certain cell, but when i am doing so the image is hiding for other cells randomly not getting the issue. Suppose i hide the image for the 2nd cell the image for 4th cell is also hiding while i scroll horizontally or vertically.
Here is my ViewController Code
import UIKit
class BookViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var dropButton: UIButton!
#IBOutlet weak var dropDownOutlet: UITableView!
#IBOutlet weak var seatMapCollection: UICollectionView!
#IBOutlet weak var dateSelecterCollection: UICollectionView!
#IBOutlet weak var timeSelecterCollection: UICollectionView!
var selectedIndexPath: IndexPath!
var dateValue = ["1","2","3","4","10","6","7","8","9","5"]
var dayValue = ["Mon","Tue","Wed","Thu","Thu","Thu","Thu","Thu","Thu","Thu"]
var month = ["jan","feb","mar","apr","Thu","Thu","Thu","Thu","Thu","Thu"]
var venue = ["Smart Cinemaz, Rupnagar","Smart Cinemaz, Fatehgarh Sahib "]
var numberSection:Int = 10
var numberOfItems:Int = 15
var seatNumber = [Int]()
var columns = [[Int]]()
var rows = [[Int]]()
var col = [2,3]
var rowno = [6,7,14]
var col1 = [5,6,7,8,9,11,12]
var rowno1 = [7]
var sectionHeader = [0,4,10]
override func viewDidLoad() {
super.viewDidLoad()
self.seatMapCollection.dataSource = self
self.seatMapCollection.delegate = self
self.seatMapCollection.reloadData()
self.seatMapCollection.maximumZoomScale = 2
self.seatMapCollection.minimumZoomScale = 0.50
self.view.sendSubview(toBack: seatMapCollection)
seatMapCollection.register(UINib(nibName: "HeaderMulticolumn", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "Header")
for seat in 0...numberOfItems-1{
seatNumber.append(seat + 1)
}
self.dateSelecterCollection.dataSource = self
self.dateSelecterCollection.delegate = self
self.timeSelecterCollection.dataSource = self
self.timeSelecterCollection.delegate = self
self.dropDownOutlet.delegate = self
self.dropDownOutlet.dataSource = self
dropButton.contentHorizontalAlignment = .left
/* let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchAction(sender:)))
seatMapCollection.addGestureRecognizer(pinchGesture)*/
columns.append(col)
columns.append(col1)
rows.append(rowno)
rows.append(rowno1)
}
#IBAction func dropDown(_ sender: Any) {
self.view.bringSubview(toFront: dropDownOutlet)
if dropDownOutlet.isHidden == true{
dropDownOutlet.isHidden = false
}else {
dropDownOutlet.isHidden = true
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView.tag == 1{
return 1
}else if collectionView.tag == 2{
return 1
}else{
return 15
}
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
if collectionView.tag == 1{
return 7
}else if collectionView.tag == 2{
return 5
}
else{
return 10 + 3
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView.tag == 1 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DateSelecterCollectionViewCell", for: indexPath) as! DateSelecterCollectionViewCell
if (self.selectedIndexPath != nil && indexPath == self.selectedIndexPath){
cell.backgroundColor = UIColor.yellow
cell.dateOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.monthOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dayOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
else{
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dateOutlet.textColor = UIColor.white
cell.monthOutlet.textColor = UIColor.white
cell.dayOutlet.textColor = UIColor.white
}
return cell
}else if collectionView.tag == 2{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TimeSelecterCollectionViewCell", for: indexPath) as! TimeSelecterCollectionViewCell
if (self.selectedIndexPath != nil && indexPath == self.selectedIndexPath){
cell.backgroundColor = UIColor.yellow
cell.timeOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
else{
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.timeOutlet.textColor = UIColor.white
}
return cell
}
else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SeatMapCollectionViewCell", for: indexPath) as! SeatMapCollectionViewCell
for r1 in 0...rows.count-1{
for c1 in 0...columns.count-1{
if (r1 == c1){
for colum in 0...columns[c1].count-1 {
for ro in 0...rows[r1].count-1{
if indexPath.row == rows[r1][ro] && indexPath.section == columns[c1][colum]{
cell.alpha = 0
}
}
}
}
}
}
for i in 0...sectionHeader.count-1{
if indexPath.section==sectionHeader[i] && indexPath.row==0{
cell.seatDetail.alpha=1
cell.seatDetail.text = "Gold - 180"
cell.seatImage.isHidden = true
}
}
//cell.seatDetail.alpha=0
return cell
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView.tag == 1{
let cell = collectionView.cellForItem(at: indexPath) as! DateSelecterCollectionViewCell
if cell.isSelected == true{
cell.backgroundColor = UIColor.yellow
cell.dateOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.monthOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dayOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
self.selectedIndexPath = indexPath
}else if collectionView.tag == 2 {
let cell = collectionView.cellForItem(at: indexPath) as! TimeSelecterCollectionViewCell
self.selectedIndexPath = nil
cell.backgroundColor = UIColor.yellow
cell.timeOutlet.textColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
if collectionView.tag == 1{
let cell = collectionView.cellForItem(at: indexPath) as! DateSelecterCollectionViewCell
self.selectedIndexPath = nil
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.dateOutlet.textColor = UIColor.white
cell.monthOutlet.textColor = UIColor.white
cell.dayOutlet.textColor = UIColor.white
}
else if collectionView.tag == 2{
let cell = collectionView.cellForItem(at: indexPath) as! TimeSelecterCollectionViewCell
self.selectedIndexPath = nil
cell.backgroundColor = UIColor(red: 44/255, green: 150/255, blue: 208/255, alpha: 1)
cell.timeOutlet.textColor = UIColor.white
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return venue.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DropDownTableViewCell") as! DropDownTableViewCell
cell.venueDetails.text = "\(venue[indexPath.row])"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! DropDownTableViewCell
dropButton.setTitle(cell.venueDetails.text, for: .normal)
tableView.isHidden = true
}
}
Here is my Custom CollectionViewlayout
import UIKit
protocol SeatMapDelegate:class {
func collectionView(Width: Double)-> Double
func collectionView(Height: Double)-> Double }
class CustomCollectionViewLayout: UICollectionViewLayout {
var delegate: SeatMapDelegate?
var CELL_HEIGHT = 35.0
var CELL_WIDTH = 35.0
let STATUS_BAR = UIApplication.shared.statusBarFrame.height
var cache = [UICollectionViewLayoutAttributes]()
var contentSize = CGSize.zero
var cellAttrsDictionary = [UICollectionViewLayoutAttributes]()
var cellPadding = 5.0
var sectionHeader = [0,4,10]
override var collectionViewContentSize: CGSize{
return self.contentSize
}
var interItemsSpacing: CGFloat = 8
// 5
var contentInsets: UIEdgeInsets {
return collectionView!.contentInset
}
override func prepare() {
var counts: Int = 0
// Cycle through each section of the data source.
if collectionView!.numberOfSections > 0 {
for section in 0...collectionView!.numberOfSections-1 {
// Cycle through each item in the section.
if collectionView!.numberOfItems(inSection: section) > 0 {
for item in 0...collectionView!.numberOfItems(inSection: section)-1 {
// Build the UICollectionVieLayoutAttributes for the cell.
let cellIndex = NSIndexPath(item: item, section: section)
/* let width: Double = 35.0
let height: Double = 35.0
CELL_WIDTH = (delegate?.collectionView(Width: width))!
CELL_HEIGHT = (delegate?.collectionView(Height: height))!*/
if counts<sectionHeader.count {
if item == 0 && section == sectionHeader[counts]{
let xPos = 0.0
let yPos = Double(section) * CELL_HEIGHT
let frame = CGRect(x: xPos, y: yPos, width: 15 * CELL_WIDTH, height: CELL_HEIGHT)
let cellFinalAttribute = frame.insetBy(dx:CGFloat(cellPadding) ,dy:CGFloat(cellPadding))
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex as IndexPath)
cellAttributes.frame = cellFinalAttribute
//cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
cellAttrsDictionary.append(cellAttributes)
counts=counts+1
break
}
}
let xPos = Double(item) * CELL_WIDTH
let yPos = Double(section) * CELL_HEIGHT
let frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
let cellFinalAttribute = frame.insetBy(dx:CGFloat(cellPadding) ,dy:CGFloat(cellPadding))
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex as IndexPath)
cellAttributes.frame = cellFinalAttribute
//cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
cellAttrsDictionary.append(cellAttributes)
}
}
}
}
// Update content size.
let contentWidth = Double(collectionView!.numberOfItems(inSection: 0)) * CELL_WIDTH
let contentHeight = Double(collectionView!.numberOfSections) * CELL_HEIGHT
self.contentSize = CGSize(width: contentWidth, height: contentHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
// Create an array to hold all elements found in our current view.
var attributesInRect = [UICollectionViewLayoutAttributes]()
// Check each element to see if it should be returned.
for cellAttributes in cellAttrsDictionary {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
// Return list of elements.
return attributesInRect
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttrsDictionary[indexPath.row]
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return false
}
}
Custom CollectionView cell class
import UIKit
class SeatMapCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var seatDetail: UILabel!
#IBOutlet weak var seatImage: UIImageView!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup() {
//self.layer.borderWidth = 1.0
// self.layer.borderColor = UIColor.gray.cgColor
// self.layer.cornerRadius = 5.0
}}
I want to changed tableviewcell's data with XMSegmentedControl(https://github.com/xaviermerino/XMSegmentedControl),
and I using switch in the
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
,but it's always print
fatal error: unexpectedly found nil while unwrapping an Optional value**,and say *segmentedControl1 is nil.
let tin = ["1","2","3","4"]
let how = ["one","two","three","four"]
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var segmentedControl1: XMSegmentedControl!
override func viewDidLoad() {
super.viewDidLoad()
let segmentedControl3 = XMSegmentedControl(frame: CGRect(x: 0, y: 70, width: self.view.frame.width, height: 44), segmentTitle: ["Hello", "World", "Three"], selectedItemHighlightStyle: XMSelectedItemHighlightStyle.topEdge)
segmentedControl3.backgroundColor = UIColor(red: 22/255, green: 150/255, blue: 122/255, alpha: 1)
segmentedControl3.highlightColor = UIColor(red: 25/255, green: 180/255, blue: 145/255, alpha: 1)
segmentedControl3.tint = UIColor.white
segmentedControl3.highlightTint = UIColor.black
self.view.addSubview(segmentedControl3)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var returnValue = 0
switch(segmentedControl1.selectedSegment)
{
case 0 :
returnValue = tin.count
case 1 :
returnValue = how.count
default :
break
}
return returnValue
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
switch(segmentedControl1.selectedSegment)
{
case 0 :
cell.textLabel?.text = tin[indexPath.row]
case 1 :
cell.textLabel?.text = how[indexPath.row]
default :
break
}
return cell
}
Can anyone help me solve this problem?
Thanks!
replace your viewDidLoad() by my code.
override func viewDidLoad() {
super.viewDidLoad()
segmentedControl1 = XMSegmentedControl(frame: CGRect(x: 0, y: 70, width: self.view.frame.width, height: 44), segmentTitle: ["Hello", "World", "Three"], selectedItemHighlightStyle: XMSelectedItemHighlightStyle.topEdge)
segmentedControl1.backgroundColor = UIColor(red: 22/255, green: 150/255, blue: 122/255, alpha: 1)
segmentedControl1.highlightColor = UIColor(red: 25/255, green: 180/255, blue: 145/255, alpha: 1)
segmentedControl1.tint = UIColor.white
segmentedControl1.highlightTint = UIColor.black
self.view.addSubview(segmentedControl1)
}
put into valuechenged method of segmentControl
DispatchQueue.main.async{
self.ttblView.reloadData()
}
You have applied wrong segmentControl . You put value in segmentedControl3 so segmentedControl1 gives nil .
I am including my code that I have implemented to filter through sortedDiscipline names.
The problem I am having --even though it is filtering through the names-- is after the IndexPath.row is changed from the filtering, the image is incorrect for the current game, and also the cell that is populated cannot be selected because the didSelectRow does not follow the broken IndexPath.
import UIKit
import Foundation
import Alamofire
import SwiftyJSON
import Firebase
import FirebaseDatabase
class AllGamesTableViewController: UITableViewController, UISearchResultsUpdating {
let urlFront = "https://www.toornament.com/disciplines/"
let urlImagePath = "/img/icon-48x48-medium.png"
var selectedRow: Int?
var newArray = [String]()
var filteredGames = [String]()
var searchController: UISearchController!
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController:nil)
searchController.dimsBackgroundDuringPresentation = true
searchController.searchBar.sizeToFit()
searchController.searchResultsUpdater = self
searchController.hidesNavigationBarDuringPresentation = false
searchController.searchBar.searchBarStyle = UISearchBarStyle.minimal
// Include the search bar within the navigation bar.
navigationItem.titleView = self.searchController.searchBar
definesPresentationContext = true
tableView.reloadData()
}
override func viewWillAppear(_ animated: Bool) {
tableView.delegate = self
tableView.dataSource = self
tableView.backgroundColor = #colorLiteral(red: 0.1137254902, green: 0.168627451, blue: 0.1764705882, alpha: 1)
self.view.backgroundColor = #colorLiteral(red: 0.1137254902, green: 0.168627451, blue: 0.1764705882, alpha: 1)
self.navigationItem.setHidesBackButton(true, animated: true)
// self.navigationItem.setHidesBackButton(true, animated: true)
}
// MARK: - Table view data source
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 {
if (searchController?.isActive)!{
return filteredGames.count
}else{
return ApiManager.shared.sortedDisipline.count
}
}
let getID = ApiManager.shared.disciplinesID
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "allGamesCell", for: indexPath)
cell.backgroundColor = UIColor(red: 29.0/255.0, green: 43.0/255.0, blue: 45.0/255.0, alpha: 1)
cell.textLabel?.textColor = #colorLiteral(red: 1, green: 0.5763723254, blue: 0, alpha: 1)
let disciplineid = ApiManager.shared.sortedDisciplineID[indexPath.row]
if (searchController?.isActive)!{
cell.textLabel?.text = filteredGames[indexPath.row]
cell.textLabel?.textColor = UIColor(red: 255.0/255.0, green: 165.0/255.0, blue: 0.0/255.0, alpha: 1)
cell.imageView?.image = UIImage(named: "\(disciplineid).png")
}else{
cell.textLabel?.textColor = UIColor(red: 255.0/255.0, green: 165.0/255.0, blue: 0.0/255.0, alpha: 1)
cell.textLabel?.text = ApiManager.shared.sortedDisipline[indexPath.row]
cell.imageView?.image = UIImage(named: "\(disciplineid).png")
}
return cell
}
func updateSearchResults(for searchController: UISearchController) {
filteredGames.removeAll(keepingCapacity: false)
//filter through the all games
filteredGames = ApiManager.shared.sortedDisipline.filter {
game in
game.lowercased().contains(searchController.searchBar.text!.lowercased())
}
// if searchController.searchBar.text != ""{
tableView.reloadData()
}
// }
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if searchController.isActive && searchController.searchBar.text != "" {
print(indexPath.row)
let DisciplineID = filteredGames[indexPath.row]
TournamentStore.shared.currentDisciplineId = DisciplineID
performSegue(withIdentifier: "tournamentList", sender: self)
} else {
let DisciplineID = ApiManager.shared.sortedDisciplineID[indexPath.row]
print("\(DisciplineID) \("did on click")")
TournamentStore.shared.currentDisciplineId = DisciplineID
performSegue(withIdentifier: "tournamentList", sender: self)
}
}
Suggestions to solve the issues.
Do not use separate arrays for disciplinesID and sortedDisipline
Use the class or struct representing discipline for both the data source array and the filteredGames array.
Get the disciplineid always directly from the discipline object. (Solves the image issue)
In didSelectRowAt get the object depending on searchController?.isActive like in the other methods (solves the indexPath issue)
PS: Initialize the search controller lazily and non-optional. That avoids a lot of question and exclamation marks.
Migrated from my comment for more explanation.
The reason your selection is incorrect is in your didSelectRowAt indexPath if you are searching you are not using the filtered list to get the ID. This is also why the image is wrong when reloading, you need to get the ID out of the filtered array if sorting
Something like this:
let id: String
if filtering {
id = filteredGames[indexPath.row]
} else {
id = ApiManager.shared.sortedDisciplineID[indexPath.row])
}
then use that id for the image and for opening it. Essentially when you sort you are changing how the names match up with the row ID's.
Most of my problem was that
searchController.dimsBackgroundDuringPresentation was set to true....it needed to be false.