I am using library SJSegmentedViewController for my project, github link to pod
Problem:
I have main view controller (FilterVC) on which I have a button "APPLY", on its action I want to access an array stored in another viewcontroller (FilterSkillVC), I am doing this using delegation, but still what I get is an empty instance
UPDATED
MY FilterVC code
import UIKit
import SJSegmentedScrollView
protocol FilterVCDelegate {
func btnApply()
}
class FilterVC: UIViewController {
var selectedSegment: SJSegmentTab?
var segmentedVC : SJSegmentedViewController?
var vcDelegate : FilterVCDelegate?
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
segmentViewInitialization()
}
#IBAction func btnApply(_ sender: Any) {
vcDelegate?.btnApply()
}
}
extension FilterVC {
var titles: [String] {
return [SegmentTitles.skillSet.rawValue,
SegmentTitles.cuisines.rawValue,
SegmentTitles.others.rawValue ]
}
var tabs: [String] {
return [StoryboardId.skillSet.rawValue,
StoryboardId.skillSet.rawValue,
StoryboardId.others.rawValue ]
}
func segmentViewInitialization() {
segmentedVC = CSSegment.setupTabs(storyboard: self.storyboard, tabs: tabs, titles: titles) as? SJSegmentedViewController
segmentedVC?.delegate = self
segmentedVC?.selectedSegmentViewHeight = 2.0
segmentedVC?.segmentTitleColor = .white
segmentedVC?.selectedSegmentViewColor = AppColor.secondary.value
segmentedVC?.segmentBackgroundColor = AppColor.primary.value
segmentedVC?.segmentViewHeight = 64.0
segmentedVC?.segmentShadow = SJShadow.light()
segmentedVC?.segmentTitleFont = AppFont.avenirMedium.size(14.0)
containerView.addSubview((segmentedVC?.view)!)
segmentedVC?.view.frame = containerView.bounds
}
}
extension FilterVC: SJSegmentedViewControllerDelegate {
func didMoveToPage(_ controller: UIViewController, segment: SJSegmentTab?, index: Int) {
if index != tabs.count-1 {
let filterVC = controller as! FilterSkillVC
filterVC.updateCurrentHeader(currentTab:SegmentTitles(rawValue: titles[index])!)
}
if selectedSegment != nil {
selectedSegment?.titleColor(.white)
}
if (segmentedVC?.segments.count)! > 0 {
selectedSegment = segmentedVC?.segments[index]
selectedSegment?.titleColor(AppColor.secondary.value)
}
}
}
My Skill VC code
import UIKit
class FilterSkillVC: UIViewController {
#IBOutlet var tblView: UITableView!
var instance = FilterVC()
lazy var arraySkills = [JSTags]()
lazy var arrayCuisines = [JSTags]()
var arrayID = [String]()
var currentHeader: SegmentTitles = .skillSet
override func viewDidLoad() {
super.viewDidLoad()
apiSkillCall()
apiCuisineCall()
registerCell(cellId: .filterListCell, forTableView: tblView)
tblView.tableFooterView = UIView()
// let instance = FilterVC()
instance.vcDelegate = self
}
func updateCurrentHeader(currentTab : SegmentTitles){
currentHeader = currentTab
tblView.reloadData()
}
//MARK: ----- Custom Methods
func countForHeader() -> NSInteger {
switch currentHeader {
case .skillSet:
return arraySkills.count
case .cuisines:
return arrayCuisines.count
default:
return 0
}
}
func titleForHeader(_ index: NSInteger) -> (name: String?, obj: AnyObject?) {
switch currentHeader {
case .skillSet:
return (name: arraySkills[index].name, obj: arraySkills[index])
case .cuisines:
return (name: arrayCuisines[index].name, obj: arrayCuisines[index])
default:
return (name: nil, obj: nil)
}
}
//MARK: ----- Handle Response Methods
func handleSkillsResponse(response: Response) {
switch response{
case .success(let response):
if let skills = response as? [JSTags] {
self.arraySkills = skills
}
case .failure(let str):
Alerts.shared.show(alert: .oops, message: /str, type: .error)
case .dataNotExist(let str):
Alerts.shared.show(alert: .oops, message: str, type: .info)
}
tblView.reloadData()
}
func handleCuisineResponse(response: Response) {
switch response{
case .success(let response):
if let cuisines = response as? [JSTags] {
self.arrayCuisines = cuisines
tblView.reloadData()
}
case .failure(let str):
Alerts.shared.show(alert: .oops, message: /str, type: .error)
case .dataNotExist(let str):
Alerts.shared.show(alert: .oops, message: str, type: .info)
}
}
//MARK: API Methods
func apiSkillCall() {
APIManager.shared.request(with: ProfileEndPoint.fetchSkills()) { (response) in
self.handleSkillsResponse(response: response)
}
}
func apiCuisineCall() {
APIManager.shared.request(with: ProfileEndPoint.fetchCuisines()) { (response) in
self.handleCuisineResponse(response: response)
}
}
}
extension FilterSkillVC : UITableViewDelegate, UITableViewDataSource, FilterListCellDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return countForHeader()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifiers.filterListCell.rawValue) as! FilterListCell
let filter = titleForHeader(indexPath.row)
cell.lblFilterLabel.text = filter.name
//Mark: Cell delegate
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 70
}
//Mark: FilterCellDelegate Method
func buttonTapped(cell: FilterListCell) {
if let indexPath = self.tblView.indexPath(for: cell) {
print("Button tapped on row \(indexPath.row)")
if currentHeader == .skillSet {
arraySkills[indexPath.row].isSelected = !arraySkills[indexPath.row].isSelected
}
else {
arrayCuisines[indexPath.row].isSelected = !arrayCuisines[indexPath.row].isSelected
}
}
}
}
extension FilterSkillVC : FilterVCDelegate {
func btnApply() {
for object in arraySkills {
if object.isSelected {
arrayID.append((object.id) ?? "")
}
}
for object in arrayCuisines {
if object.isSelected {
arrayID.append((object.id) ?? "")
}
}
}
}
You are losing the reference to the instance as soon as the viewDidLoad method is completed.
Make instance a global Variable.
Like so :
import UIKit
class FilterSkillVC: UIViewController {
#IBOutlet var tblView: UITableView!
var instance = FilterVC() //New line added here.
lazy var arraySkills = [JSTags]()
lazy var arrayCuisines = [JSTags]()
var arrayID = [String]()
var currentHeader: SegmentTitles = .skillSet
override func viewDidLoad() {
super.viewDidLoad()
apiSkillCall()
apiCuisineCall()
registerCell(cellId: .filterListCell, forTableView: tblView)
tblView.tableFooterView = UIView()
//let instance = FilterVC() //Commented this.
instance.vcDelegate = self
}
More updates :
In the didMoveToPage method, you are getting a reference to a FilterVC (from a storyboard ??), now this instance of FilterVC is different from the instance of filterVC we created.
Please add this change and try :
func didMoveToPage(_ controller: UIViewController, segment: SJSegmentTab?, index: Int) {
if index != tabs.count-1 {
let filterVC = controller as! FilterSkillVC
filterVC.updateCurrentHeader(currentTab:SegmentTitles(rawValue: titles[index])!)
self.vcDelegate = filterVC // <== Updated this line.
}
Related
I need to search in the tableview.I have tableview and textfield.While clicking on the textfield it must search the tableview.
my model:-
class SearchModel: NSObject {
var restaurantname :String!
init?(dictionary :JSONDictionary) {
guard let name = dictionary["name"] as? String else {
return
}
self.restaurantname = name
}
}
my viewmodel:-
class SearchViewModel: NSObject {
var datasourceModel:SearchDataSourceModel
init(withdatasource newDatasourceModel: SearchDataSourceModel) {
datasourceModel = newDatasourceModel
}
func datafordisplay(atindex indexPath: IndexPath) -> SearchModel{
return datasourceModel.dataListArray![indexPath.row]
}
func numberOfRowsInSection(section:Int) -> Int {
return (datasourceModel.dataListArray?.count)!
}
func loadData(completion :#escaping (_ isSucess:Bool) -> ()){
loadFromWebserviceData { (newDataSourceModel) in
if(newDataSourceModel != nil)
{
self.datasourceModel = newDataSourceModel!
completion(true)
}
else{
completion(false)
}
}
}
//}
func loadFromWebserviceData(completion :#escaping (SearchDataSourceModel?) -> ()){
//with using Alamofire ..............
Alamofire.request("http://www.example.com").validate(statusCode: 200..<300).validate(contentType: ["application/json"]).responseJSON{ response in
switch response.result{
case .success(let data):
print("success",data)
let result = response.result
if let wholedata = result.value as? [String:Any]{
if let data = wholedata["data"] as? Array<[String:Any]>{
// print(data["name"] as! String)
print(data)
print(response)
let newDataSource:SearchDataSourceModel = SearchDataSourceModel(array: data)
completion(newDataSource)
// }
}
}
// case .failure(let data):
// print("fail",data)
case .failure(let encodingError ):
print(encodingError)
// if response.response?.statusCode == 404{
print(encodingError.localizedDescription)
completion(nil)
// }
}
}}
}
my datasource model:-
class SearchDataSourceModel: NSObject {
var dataListArray:Array<SearchModel>? = []
init(array :Array<[String:Any]>?) {
super.init()
var newArray:Array<[String:Any]> = []
if array == nil{
// newArray = self.getJsonDataStored44()
}
else{
newArray = array!
}
var datalist:Array<SearchModel> = []
for dict in newArray{
let model = SearchModel(dictionary: dict)
datalist.append(model!)
}
self.dataListArray = datalist
}
}
my viewcontroller:-
class SearchViewController: UIViewController,UITableViewDelegate,UITableViewDataSource, UISearchBarDelegate,UITextFieldDelegate {
#IBOutlet private weak var tableView: UITableView!
!
#IBOutlet weak var txt: UITextField!
var filteredSearchArray = NSMutableArray()
private var searchViewModel :SearchViewModel!
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?, withViewModel viewModel:SearchViewModel) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
searchViewModel = viewModel
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var filteredData: [String]!
override func viewDidLoad() {
super.viewDidLoad()
txt.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
searchViewModel.loadData { (isSuccess) in
if(isSuccess == true)
{
self.tableView .reloadData()
}
else{
}
}
}
#objc private func textFieldDidChange(textField: UITextField) {
if textField.text == "" {
self .viewDidLoad()
}else{
filterContentForSearchText(searchText: textField.text!)
}
}
func filterContentForSearchText(searchText: String) {
filteredSearchArray = NSMutableArray(array:(searchViewModel.datasourceModel.dataListArray?.filter({(ele:AnyObject) -> Bool in
return (ele as! SearchModel).restaurantname.lowercased().contains(searchText.lowercased())
}))!)
tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchViewModel.numberOfRowsInSection(section: section)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "searchcell"
var cell: SearchCell! = tableView.dequeueReusableCell(withIdentifier: identifier) as? SearchCell
if cell == nil {
tableView.register(UINib(nibName: "SearchCell", bundle: nil), forCellReuseIdentifier: identifier)
cell = tableView.dequeueReusableCell(withIdentifier: identifier) as?SearchCell
}
cell.setsearchData(search: searchViewModel.datafordisplay(atindex: indexPath))
return cell
}
}
my tableviewcell:-
class SearchCell: UITableViewCell {
#IBOutlet weak var name: 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
}
func setsearchData(search:SearchModel)
{
self.name.text = search.restaurantname
}
}
This is my code but in the filteredSearchArray always shows as 0 element.
Here the list of names is displaying but clicking on the textfield it doesn't searching and not reloading. How to solve the problem.
The data is not coming in this code:-
func filterContentForSearchText(searchText: String) {
filteredSearchArray = NSMutableArray(array:(searchViewModel.datasourceModel.dataListArray?.filter({(ele:AnyObject) -> Bool in
return (ele as! SearchModel).restaurantname.lowercased().contains(searchText.lowercased())
}))!)
tableView.reloadData()
}
First of all one important thing don't use NSArray, NSDictionary in swift use Array, Dictionary instead.
I have made a change in your model class:
class SearchModel: NSObject {
var restaurantname :String!
init(dictionary :JSONDictionary) {
self.restaurantname = dictionary["name"] as? String ?? ""
}
}
Now filter your array like this:
filteredSearchArray = searchViewModel.datasourceModel.dataListArray?.filter {$0.restaurantname.lowercased().contains(searchText.lowercased())}
And now pass filteredSearchArray in tableView datasource then reload the table. You can take a bool variable isSearching to check which array you have to pass in datasource the filtered one the original. Toggle this isSearching in textFieldDidBeginEiditng and textFieldDidEndEiditng method.
I have tested it by below example in my playground:
var models: Array<SearchModel> = [SearchModel.init(dictionary: ["name": "Khalsa Dhaba"]), SearchModel.init(dictionary: ["name": "Yo! China"]), SearchModel.init(dictionary: ["name": "Sher-e-punjab"]), SearchModel.init(dictionary: ["name": "Haveli"])]
let result = models.filter {$0.restaurantname.lowercased().contains("o!".lowercased())}
print(result)
It works fine!
Secondly I noticed you're reloading your view by calling self.viewDidLoad() method which you should not call ever this calls itself and it is a function of viewContoller lifecycle. Call tableView.reloadData() instead.
I created a UIViewController class with a tableView to show different places in the cells, i'm working with Alamofire and Google API (maps, places), the only problem is that when i run the project the cells are empty, this is my controller class:
import UIKit
class SelectClass: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var list : [QCategoryy] = [QCategoryy]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
self.title = "Categories"
list = NearbyPlaces.getCategories()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
list.sort() { $0.views > $1.views}
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func backTapp(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
#IBAction func doneTapp(_ sender: Any) {
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return list.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier = "CATEGORY_CELL"
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
cell.textLabel?.text = list[indexPath.row].name
return cell
}
let nearbySearchSegueIdentifier = "goToMcourse"
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.performSegue(withIdentifier: nearbySearchSegueIdentifier, sender: list[indexPath.row])
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == nearbySearchSegueIdentifier {
guard let category = sender as? QCategoryy else {
return
}
if let vc = segue.destination as? CourseClass2 {
vc.category = category
}
}
}
}
extension QCategoryy {
private static let ketPrefix = "category-"
var views:Int {
get {
return UserDefaults.standard.integer(forKey: QCategoryy.ketPrefix + name)
}
}
func markView() {
UserDefaults.standard.set(views + 1, forKey: QCategoryy.ketPrefix + name)
}
}
and these are the two classes that work with it:
import Foundation
import UIKit
import CoreLocation
import Alamofire
class NearbyPlaces {
static func getCategories() -> [QCategoryy] {
let list:[QCategoryy] = ["Bakery", "Doctor", "School", "Taxi_stand", "Hair_care", "Restaurant", "Pharmacy", "Atm", "Gym", "Store", "Spa"]
return list
}
static let searchApiHost = "https://maps.googleapis.com/maps/api/place/nearbysearch/json"
static let googlePhotosHost = "https://maps.googleapis.com/maps/api/place/photo"
static func getNearbyPlaces(by category:String, coordinates:CLLocationCoordinate2D, radius:Int, token: String?, completion: #escaping (QNearbyPlacesResponse?, Error?) -> Void) {
var params : [String : Any]
if let t = token {
params = [
"key" : AppDelegate.googlePlacesAPIKey,
"pagetoken" : t,
]
} else {
params = [
"key" : AppDelegate.googlePlacesAPIKey,
"radius" : radius,
"location" : "\(coordinates.latitude),\(coordinates.longitude)",
"type" : category.lowercased()
]
}
Alamofire.request(searchApiHost, parameters: params, encoding: URLEncoding(destination: .queryString)).responseJSON { response in
if let error = response.error {
completion(nil, error)
}
if let response = QNearbyPlacesResponse(dic : response.result.value as? [String : Any]) {
completion(response, nil)
}
else {
completion(nil, QNearbyPlacesResponseError.noParsingDone)
}
}
}
static func googlePhotoURL(photoReference:String, maxWidth:Int) -> URL? {
return URL.init(string: "\(googlePhotosHost)?maxwidth=\(maxWidth)&key=\(AppDelegate.googlePlacesAPIKey)&photoreference=\(photoReference)")
}
}
enum QNearbyPlacesResponseError : Error {
case noParsingDone
}
struct QNearbyPlacesResponse {
var nextPageToken: String?
var status: String = "NOK"
var places: [QPlace]?
init?(dic:[String : Any]?) {
nextPageToken = dic?["next_page_token"] as? String
if let status = dic?["status"] as? String {
self.status = status
}
if let results = dic?["results"] as? [[String : Any]]{
var places = [QPlace]()
for place in results {
places.append(QPlace.init(placeInfo: place))
}
self.places = places
}
}
func canLoadMore() -> Bool {
if status == "OK" && nextPageToken != nil && nextPageToken?.characters.count ?? 0 > 0 {
return true
}
return false
}
}
and
struct QCategoryy {
var name:String
init(name:String) {
self.name = name
}
}
extension QCategoryy: ExpressibleByStringLiteral {
init(stringLiteral value: String) {
self.name = value
}
init(unicodeScalarLiteral value: String) {
self.init(name: value)
}
init(extendedGraphemeClusterLiteral value: String) {
self.init(name: value)
}
}
it seems to me that it's all right, i can not understand why when i go into my uiviewcontroller the tableView has all the empty cells, here there is also a screen of what i see when running the project
hope someone can find the issue
Try with:
tableView.dataSource = self
Try adding:
tableView.dataSource = self
tableView.delegate = self`
to your viewDidLoad()
I am currently using a table view to display a menu, in which people can click on the add or subtract buttons to increase/decrease their order.
This table view has approximately 30 items and so you have to scroll down to get to all the menu items. The problem is, when you scroll down, the table view cells above the scroll (that are now hidden) lose the data that they have just contained.
For example, if you have a menu item that you have ordered 2 of an item, that 2 on the label has now turned back to 0. This is very object oriented so I am not sure why this is happening.
My table view class:
#IBOutlet weak var appetizerTableView: UITableView!
var appetizerList = [OrderModel]()
let ref = FIRDatabase.database().reference()
override func viewDidLoad() {
appetizerTableView.delegate = self
appetizerTableView.dataSource = self
ref.child("Broadway").child("AppetizerDishes").observeSingleEventOfType(.Value, withBlock: { snapshot in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
print("WILL: \(snap)")
if let postDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let post = OrderModel(postkey: key, postData: postDict)
self.appetizerList.append(post)
}
}
}
self.appetizerTableView.reloadData()
})
}
var data=[OrderModel]()
func addButtonAction(addedList:[String:Float]) {
print("WILLCOHEN:\(addedList)")
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return appetizerList.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let post = appetizerList[indexPath.row]
if let cell = appetizerTableView.dequeueReusableCellWithIdentifier("OrderCell") as? OrderCell{
cell.configureCell(post)
cell.delegate = self
return cell
} else {
return OrderCell()
}
}
}
My cell model class:
class OrderModel {
private var _dishName: String!
private var _dishDescription: String!
private var _numberOfOrders: Int!
private var _postKey: String!
private var _dishPrice: Float!
var dishName: String {
return _dishName
}
var dishDescription: String {
return _dishDescription
}
var numberOfOrders: Int {
get {
return _numberOfOrders
}
set (newVal) {
_numberOfOrders = newVal
}
}
var postKey: String {
return _postKey
}
var dishPrice: Float {
return _dishPrice
}
init(dishName: String, dishDescription: String, numberOfOrders: Int) {
self._dishName = dishName
self._dishDescription = dishDescription
}
init(postkey: String, postData: Dictionary<String, AnyObject>) {
self._postKey = postkey
if let dishName = postData["dishName"] as? String {
self._dishName = dishName
}
if let dishDescription = postData["dishDescription"] as? String {
self._dishDescription = dishDescription
}
if let numberOfOrders = postData["anumberOfOrders"] as? Int {
self._numberOfOrders = numberOfOrders
}
if let dishPrice = postData["dishPrice"] as? Float32 {
self._dishPrice = dishPrice
}
}
}
My cell class:
protocol ClassNameDelegate:class {
func addButtonAction(addedList:[String:Float])
}
var addedList: [String:Float] = [:]
class OrderCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
}
var post: OrderModel!
var link: Link!
#IBOutlet weak var dishName: UILabel!
#IBOutlet weak var dishDescriptionAndPrice: UILabel!
#IBOutlet weak var numberOfOrders: UILabel!
#IBOutlet weak var addOrderBtn: UIButton!
#IBOutlet weak var subtractOderBtn: UIButton!
weak var delegate: ClassNameDelegate?
#IBAction func addButtonPressed(sender: AnyObject) {
if post.numberOfOrders == 9 {
numberOfOrders.text = "9"
} else {
if addedList[post.dishName] != nil {
addedList[post.dishName] = post.dishPrice
} else {
addedList["\(post.dishName) \(Int(numberOfOrders.text!)! + 1)"] = post.dishPrice
}
post.numberOfOrders = post.numberOfOrders - 1
numberOfOrders.text = "\(post.numberOfOrders)"
}
if delegate != nil {
delegate?.addButtonAction(addedList)
}
}
#IBAction func subtractButtonPressed(sender: AnyObject) {
if post.numberOfOrders == 0 {
numberOfOrders.text = "0"
} else {
post.numberOfOrders = post.numberOfOrders + 1
numberOfOrders.text = "\(post.numberOfOrders)"
}
}
func getOrders() -> Dictionary<String, Float> {
return addedList
}
func configureCell(post: OrderModel) {
self.post = post
self.dishName.text = post.dishName
self.dishDescriptionAndPrice.text = post.dishDescription
self.numberOfOrders.text = "0"
}
}
I should mention that I am pulling my table view data from Firebase.
Thank you in advance for any help or suggestions, it is very much appreciated.
You are calling configureCell(post:) on every cell, and in the configureCell(post:) function you set the text value of the numbersOfOrders label to "0". You should probably set the text to a value in the OrderModel/post argument.
Also, you should be sure to always call configureCell(post:) (you are not calling it if you have to manually create an OrderCell), so your tableView(tableView:cellForRowAtIndexPath:) function should look like this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let post = appetizerList[indexPath.row]
let cell = appetizerTableView.dequeueReusableCellWithIdentifier("OrderCell") as? OrderCell ?? OrderCell()
cell.configureCell(post)
cell.delegate = self
return cell
}
I have one screen like the following picture:
I uploaded list with student name by using custom cell as you are seeing and I want when click on save button save the status of student in array , I initialized array with 0 for all student at the first time and when the status of switch is enabled then this value at the clicked cell index converted to 1 but I couldn't make that when the click action happened on switch this is only now happening when click on the cell ( row ) how I can do the same thing when only change the status of switch to update the array without click on complete row at table
Code of main view :
import UIKit
class teacherAttendanceVC: UIViewController , UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var studentlistTable: UITableView!
#IBOutlet weak var loadIndicator: UIActivityIndicatorView!
var username:String?
var classID: String?
var branchID: String?
var normal_id = [String]()
var student_name = [String]()
var student_attendance = [String]()
//Sent Data
var n_id = ""
var stu_name = ""
#IBAction func backButton(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil )
}
override func viewDidLoad() {
super.viewDidLoad()
studentlistTable.delegate = self
studentlistTable.dataSource = self
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
username = prefs.objectForKey("user")as! String
classID = prefs.objectForKey("ClassID")as! String
branchID = prefs.objectForKey("BranchID")as! String
self.loadIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
self.loadList()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.loadIndicator.stopAnimating()
self.studentlistTable.reloadData()
})
});
}
override func viewDidAppear(animated: Bool) {
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return normal_id.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//This method to define each cell at Table View
let cell = self.studentlistTable.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! teacherAttendanceCell
cell.studentNameLabel.text = student_name[indexPath.row]
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Get Cell Label
let currentCell = studentlistTable.cellForRowAtIndexPath(indexPath) as! teacherAttendanceCell!
student_attendance[indexPath.row] = currentCell.status
}
#IBAction func saveButton(sender: AnyObject) {
print(student_attendance) // this only to ensure from the final array before sending to server
}
func loadList()
{
var normallink = "myurl"
normallink = normallink + "?classid=" + self.classID! + "&branchid=" + self.branchID!
print(normallink)
var studentParentURL:NSURL = NSURL (string: normallink)!
let data = NSData(contentsOfURL: studentParentURL)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
if let alldata = json["data"] as? [[String: AnyObject]] {
for onedata in alldata {
if let no_id = onedata["id"] as? String {
normal_id.append(no_id)
}
if let s_name = onedata["studentName"] as? String {
student_name.append(s_name)
}
}
}
} catch {
print("Error Serializing JSON: \(error)")
}
if(normal_id.count != 0)
{
for i in 1...self.normal_id.count
{
self.student_attendance.append("0")
}
}
print(normal_id.count)
print(student_name.count)
}
}
Cell Code :
class teacherAttendanceCell: UITableViewCell {
#IBOutlet weak var studentNameLabel: UILabel!
#IBOutlet weak var attendSwitch: UISwitch!
var status:String = ""
override func awakeFromNib() {
super.awakeFromNib()
if(attendSwitch.on)
{
status = "1"
print("ON")
}
else{
status = "0"
print("OFF")
}
attendSwitch.addTarget(self, action: "stateChanged:", forControlEvents: UIControlEvents.ValueChanged)
}
func stateChanged(switchState: UISwitch) {
if switchState.on {
status = "1"
print("ON")
} else {
status = "0"
print("OFF")
}
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
#IBAction func attendSwitchChanged(sender: AnyObject) {
}
}
Updated:
Main View Controller:
import UIKit
class teacherAttendanceVC: UIViewController , UITableViewDataSource,UITableViewDelegate,CellInfoDelegate {
#IBOutlet weak var studentlistTable: UITableView!
#IBOutlet weak var loadIndicator: UIActivityIndicatorView!
var username:String?
var classID: String?
var branchID: String?
var normal_id = [String]()
var student_name = [String]()
var student_attendance = [String]()
//Sent Data
var n_id = ""
var stu_name = ""
#IBAction func backButton(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil )
}
override func viewDidLoad() {
super.viewDidLoad()
studentlistTable.delegate = self
studentlistTable.dataSource = self
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
username = prefs.objectForKey("user")as! String
classID = prefs.objectForKey("ClassID")as! String
branchID = prefs.objectForKey("BranchID")as! String
self.loadIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
self.loadList()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.loadIndicator.stopAnimating()
self.studentlistTable.reloadData()
})
});
}
override func viewDidAppear(animated: Bool) {
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return normal_id.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//This method to define each cell at Table View
let cell = self.studentlistTable.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! teacherAttendanceCell
cell.delegate = self
cell.studentNameLabel.text = student_name[indexPath.row]
student_attendance[indexPath.row] = cell.status
//print(student_attendance.count)
//let currentCell = studentlistTable.cellForRowAtIndexPath(indexPath) as! teacherAttendanceCell!
// student_attendance.append(cell.status)
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
// Get Cell Label
// let currentCell = studentlistTable.cellForRowAtIndexPath(indexPath) as! teacherAttendanceCell!
// student_attendance[indexPath.row] = currentCell.status
//print("OK Status here!" + String(student_attendance.count))
}
#IBAction func saveButton(sender: AnyObject) {
print(student_attendance)
}
func loadList()
{
var normallink = "mylinkhere"
normallink = normallink + "?classid=" + self.classID! + "&branchid=" + self.branchID!
print(normallink)
var studentParentURL:NSURL = NSURL (string: normallink)!
let data = NSData(contentsOfURL: studentParentURL)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
if let alldata = json["data"] as? [[String: AnyObject]] {
for onedata in alldata {
if let no_id = onedata["id"] as? String {
normal_id.append(no_id)
}
if let s_name = onedata["studentName"] as? String {
student_name.append(s_name)
}
}
}
} catch {
print("Error Serializing JSON: \(error)")
}
if(normal_id.count != 0)
{
for i in 1...self.normal_id.count
{
self.student_attendance.append("0")
}
}
print(normal_id.count)
print(student_name.count)
}
func processThatNumber(theStatus: String) {
print("out : \(theStatus)")
}
}
protocol CellInfoDelegate {
func processThatNumber(theStatus: String)
}
Cell View Controller:
import UIKit
class teacherAttendanceCell: UITableViewCell{
#IBOutlet weak var studentNameLabel: UILabel!
#IBOutlet weak var attendSwitch: UISwitch!
var status:String = ""
var delegate: CellInfoDelegate?
override func awakeFromNib() {
super.awakeFromNib()
if(attendSwitch.on)
{
status = "1"
print("ON")
}
else{
status = "0"
print("OFF")
}
attendSwitch.addTarget(self, action: "stateChanged:", forControlEvents: UIControlEvents.ValueChanged)
}
func stateChanged(switchState: UISwitch) {
if switchState.on {
status = "1"
print("ON")
} else {
status = "0"
print("OFF")
}
if let delegate = self.delegate {
delegate.processThatNumber(self.status)
}
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
#IBAction func attendSwitchChanged(sender: AnyObject) {
}
}
There are few ways to do this: using closure or delegate, but I preferred to use delegate.
Create a delegate for your teacherAttendanceCell cell like in this answer https://stackoverflow.com/a/25792213/2739795
Make you teacherAttendanceVC conforms the delegate
Each time when cellForRowAtIndexPath calls set cell.delegate = self. Also return the cell into your delegate method
Call method from delegate insidestateChanged
And when delegate method calls you can get an index if switched cell
tableView.indexPathForCell(cellFromParam)
I am using this tutorial to auto-complete the google places.
I have installed the alamofire and swiftyJSON through cocoapads.
My issue is When I enter text in searchbar, nothing happens.
On my ViewControlller:
let gpaViewController = GooglePlacesAutocomplete(
apiKey: "MY-API-KEY",
placeType: .Address
)
gpaViewController.placeDelegate = self
presentViewController(gpaViewController, animated: true, completion: nil)
On my GooglePlacesAutoComplete View Controller:
import UIKit
import Alamofire
import SwiftyJSON
enum PlaceType: CustomStringConvertible {
case All
case Geocode
case Address
case Establishment
case Regions
case Cities
var description : String {
switch self {
case .All: return ""
case .Geocode: return "geocode"
case .Address: return "address"
case .Establishment: return "establishment"
case .Regions: return "regions"
case .Cities: return "cities"
}
}
}
struct Place {
let id: String
let description: String
}
protocol GooglePlacesAutocompleteDelegate {
func placeSelected(place: Place)
func placeViewClosed()
}
Only this set of codes is called:
class GooglePlacesAutocomplete: UINavigationController {
var gpaViewController: GooglePlacesAutocompleteContainer?
var placeDelegate: GooglePlacesAutocompleteDelegate? {
get { return gpaViewController?.delegate }
set { gpaViewController?.delegate = newValue }
}
convenience init(apiKey: String, placeType: PlaceType = .All) {
let gpaViewController = GooglePlacesAutocompleteContainer(
apiKey: apiKey,
placeType: placeType
)
self.init(rootViewController: gpaViewController)
self.gpaViewController = gpaViewController
let closeButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Stop, target: self, action: "close")
gpaViewController.navigationItem.leftBarButtonItem = closeButton
gpaViewController.navigationItem.title = "Enter Address"
}
func close() {
placeDelegate?.placeViewClosed()
}
}
No indication of this:
class GooglePlaceSearchDisplayController: UISearchDisplayController {
override func setActive(visible: Bool, animated: Bool) {
if active == visible { return }
searchContentsController.navigationController?.navigationBarHidden = true
super.setActive(visible, animated: animated)
searchContentsController.navigationController?.navigationBarHidden = false
if visible {
searchBar.becomeFirstResponder()
} else {
searchBar.resignFirstResponder()
}
}
}
// MARK: - GooglePlacesAutocompleteContainer
class GooglePlacesAutocompleteContainer: UIViewController {
var delegate: GooglePlacesAutocompleteDelegate?
var apiKey: String?
var places = [Place]()
var placeType: PlaceType = .All
convenience init(apiKey: String, placeType: PlaceType = .All) {
self.init(nibName: "GooglePlacesAutocomplete", bundle: nil)
self.apiKey = apiKey
self.placeType = placeType
}
override func viewDidLoad() {
super.viewDidLoad()
let tv: UITableView? = searchDisplayController?.searchResultsTableView
tv?.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
}
Or this:
// MARK: - GooglePlacesAutocompleteContainer (UITableViewDataSource / UITableViewDelegate)
extension GooglePlacesAutocompleteContainer: UITableViewDataSource, UITableViewDelegate {
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.searchDisplayController?.searchResultsTableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell?
// Get the corresponding candy from our candies array
let place = self.places[indexPath.row]
// Configure the cell
cell!.textLabel!.text = place.description
cell!.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
return cell!
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
delegate?.placeSelected(self.places[indexPath.row])
}
}
// MARK: - GooglePlacesAutocompleteContainer (UISearchDisplayDelegate)
extension GooglePlacesAutocompleteContainer: UISearchDisplayDelegate {
func searchDisplayController(controller: UISearchDisplayController, shouldReloadTableForSearchString searchString: String!) -> Bool {
getPlaces(searchString)
return false
}
private func getPlaces(searchString: String) {
let url = "https://maps.googleapis.com/maps/api/place/autocomplete/json"
Alamofire.request(.GET, url).responseJSON { response in
switch response.result {
case .Success(let data):
let json = JSON(data)
let name = json["name"].stringValue
print(name)
case .Failure(let error):
print("Request failed with error: \(error)")
}
}
}
}
Apologies for long code. Am not sure, where I made a mistake.
I also set the delegate for searchBar in xib
I double checked the installation of Cocoapads, Alamofire and SwiftyJson. Can someone please help me? I'm new to these things..
You Have To Make Object Of UISearchBar Like This...
lazy var searchBar : UISearchBar = UISearchBar()
In Did Load
searchBar.delegate = self