Swift - Tableview not updating properly with search queries - arrays

I'm using the search bar controller with a tableview. I'm fetching the contacts on my phone to populate the tableview. Here's my code for this part.
func fetchContacts(){
let key = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey] as [CNKeyDescriptor]
let request = CNContactFetchRequest(keysToFetch: key)
try! contactStore.enumerateContacts(with: request) {(contact, stoppingPointer) in
let name = "\(contact.givenName) \(contact.familyName)"
let number = contact.phoneNumbers.first?.value.stringValue
for numbero in contact.phoneNumbers {
if let number = numbero.value as? CNPhoneNumber,
let label = numbero.label {
var contactToAppend = ContractStruct(givenName: name, number: number.stringValue)
self.contacts.append(contactToAppend)
}
}
}
tableView.reloadData()
}
It retrieves the contact with different phone numbers properly and then displays in the tableview. I've also added multi selection on the tableview to be able to select multiple contacts to continue with my flow of the app.
My issue is when I'm searching for the contact in the search bar , it always gives me the wrong contacts in my tableview. It comes up with the same name always at the top. Returns wrong contact
Now if I print my filteredcontact list , it returns the proper contact that should have been displayed but it is not displayed on the tableview. Here's my code for the search
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text! == "" {
filteredContacts = contacts
} else {
// Filter the results
filteredContacts = contacts.filter { $0.givenName.lowercased().contains(searchBar.text!.lowercased())
}
}
print(filteredContacts)
tableView.reloadData()
}
And here's my full class:
class ContactsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
var contactStore = CNContactStore()
var contacts = [ContractStruct]()
var filteredContacts = [ContractStruct]()
var setSelectedItems: Set<Int> = []
var searching = false
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
contactStore.requestAccess(for: .contacts) {(success, error) in
if success {
print("Authorisation Successful")
}
self.fetchContacts()
}
filteredContacts = contacts
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return filteredContacts.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
if setSelectedItems.contains(indexPath.row) {
cell.accessoryType = .checkmark
}
else {
cell.accessoryType = .none
}
let contactToDisplay = contacts[indexPath.row]
cell.textLabel?.text = contactToDisplay.givenName
cell.detailTextLabel?.text = contactToDisplay.number
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if setSelectedItems.contains(indexPath.row) {
setSelectedItems.remove(indexPath.row)
} else {
setSelectedItems.insert(indexPath.row)
}
tableView.reloadRows(at: [indexPath], with: .none)
print(setSelectedItems)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchBar.text! == "" {
filteredContacts = contacts
} else {
// Filter the results
filteredContacts = contacts.filter { $0.givenName.lowercased().contains(searchBar.text!.lowercased())
}
}
print(filteredContacts)
tableView.reloadData()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searching = false
searchBar.text = ""
tableView.reloadData()
}
func fetchContacts(){
let key = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey] as [CNKeyDescriptor]
let request = CNContactFetchRequest(keysToFetch: key)
try! contactStore.enumerateContacts(with: request) {(contact, stoppingPointer) in
let name = "\(contact.givenName) \(contact.familyName)"
let number = contact.phoneNumbers.first?.value.stringValue
for numbero in contact.phoneNumbers {
if let number = numbero.value as? CNPhoneNumber,
let label = numbero.label {
var contactToAppend = ContractStruct(givenName: name, number: number.stringValue)
self.contacts.append(contactToAppend)
}
}
}
tableView.reloadData()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}

Just replace contacts[indexPath.row] to filteredContacts[indexPath.row] in cellForRowAt function of tableView delegate.
Because your filtered results stored in filteredContacts and your tableView delegate functions use filteredContacts

I had to replace filteredContacts[indexPath.row] in cellForRowAt for it to work.

Related

UICollectionView in UITableView - I want to show data in CollectionVewCell

I want to show data in UICollectionView. Which is coming from UITableView cell. My main concern is this. I am passing a key catgID from cellForRowAt in another API and getting data from it. But data is not coming proper way.
I am passing catgID from cellForRowAt and getting in another API which will show the list of data for UICollectionViewCells. Now data is coming but not in proper way.
This is my UITableView class for tableview index.
import UIKit
import Reachability
import Alamofire
var arrayMenuProducts = [structMenuProducts]()
struct structMenuProducts {
var id:Int
var product_name:String
var category:String
var product_image:String
var price:String
var unit_price:Double
var addons:NSArray
}
class MenuVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
var reachability = Reachability()!
#IBOutlet weak var tableview: UITableView!
var arrayMenuCat = [structMenuCat]()
struct structMenuCat{
var id:Int
var category_name:String
}
override func viewDidLoad() {
super.viewDidLoad()
menuVegAPI()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayMenuCat.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
catgID = arrayMenuCat[indexPath.row].id
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell1") as! MenuTableCell
cell.lblCategoryTitle.text = arrayMenuCat[indexPath.row].category_name
cell.collectionviewOne.reloadData()
// let catid = arrayMenuCat[indexPath.row].id
// print(catid)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 216
}
func menuVegAPI()
{
if (reachability.connection == .wifi) || (reachability.connection == .cellular)
{
arrayMenuCat.removeAll()
SwiftLoader.show(animated: true)
let url = BaseUrl + ViewController.sharedInstance.menuCategory
print(url)
Alamofire.request(url, method: .get, parameters: nil, encoding: URLEncoding.default).responseJSON { response in
SwiftLoader.hide()
switch response.result {
case .success:
let json = response.result.value
print(json)
let code = (json as AnyObject).object(forKey: "code") as! Int
print(code)
if code == 200
{
let data = (json as AnyObject).object(forKey: "data") as? NSArray
for alldata in data!
{
let id = (alldata as AnyObject).object(forKey: "id") as! Int
let category_name = (alldata as AnyObject).object(forKey: "category_name") as! String
let arr = structMenuCat(id: id, category_name: category_name)
self.arrayMenuCat.append(arr)
// self.menuProductsAPI(categoryid: id)
}
self.tableview.reloadData()
}
else
{
}
case .failure:
print("error")
}
}
}
else
{
alert(title: "", message: "Please Check Your Internet Connection")
}
}
}
This is my TableViewCell type class. In this class I am show data on CollectionView. Its code is here
import UIKit
import Alamofire
import Reachability
var catgID : Int!
var collectionreload : UICollectionView?
class MenuTableCell: UITableViewCell, UICollectionViewDataSource, UICollectionViewDelegate {
var reachability = Reachability()!
#IBOutlet weak var lblCategoryTitle: UILabel!
#IBOutlet weak var collectionviewOne: UICollectionView!
var arrayMenuProducts = [structMenuProducts]()
struct structMenuProducts {
var id:Int
var product_name:String
var category:String
var product_image:String
var price:String
var unit_price:Double
var addons:NSArray
}
override func awakeFromNib() {
super.awakeFromNib()
collectionreload = self.collectionviewOne
print(arrayMenuProducts)
print(catgID ?? 0)
menuProductsAPI(categoryid: catgID!)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrayMenuProducts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CellRID", for: indexPath) as! MenuCollectionViewCell
let abc = arrayMenuProducts[indexPath.row].product_name
print(abc)
// if catgID == Int(arrayMenuProducts[indexPath.row].category)
// {
cell.lblTitleForVeg.text = arrayMenuProducts[indexPath.row].product_name
cell.lblForPriceVeg.text = "$\(arrayMenuProducts[indexPath.row].unit_price)"
}
func menuProductsAPI(categoryid:Int)
{
if (reachability.connection == .wifi) || (reachability.connection == .cellular)
{
SwiftLoader.show(animated: true)
arrayMenuProducts.removeAll()
let url = BaseUrl + ViewController.sharedInstance.menuProducts + "categoryid=\(categoryid)"
print(url)
Alamofire.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default).responseJSON { response in
switch response.result {
case .success:
let json = response.result.value
print(json)
// self.tableview.reloadData()
let code = (json as AnyObject).object(forKey: "code") as! Int
print(code)
if code == 200
{
let data = (json as AnyObject).object(forKey: "data") as? NSArray
DispatchQueue.main.async {
for alldata in data!
{
let id = (alldata as AnyObject).object(forKey: "id") as! Int
let product_name = (alldata as AnyObject).object(forKey: "product_name") as! String
let category = (alldata as AnyObject).object(forKey: "category") as! String
let product_image = (alldata as AnyObject).object(forKey: "product_image") as! String
let price = (alldata as AnyObject).object(forKey: "price") as! String
let unit_price = (alldata as AnyObject).object(forKey: "unit_price") as! Double
let addons = (alldata as AnyObject).object(forKey: "addons") as? NSArray
let arr = structMenuProducts(id: id, product_name: product_name, category: category, product_image: product_image, price: price, unit_price: unit_price, addons: addons!)
self.arrayMenuProducts.append(arr)
}
self.collectionviewOne.reloadData()
SwiftLoader.hide()
}
}
else
{
}
case .failure:
print("error")
}
}
}
else
{
// alert(title: "", message: "Please Check Your Internet Connection")
}
}
}
I want to show data coming in CollectionView in a proper formate. If Tableview index == 0 and Category id is coming 10 then. Category id 10 will first then one by one in a sequence I want to pass category id. In my case Category id is not coming in a queue.
Update the tableview datasource method as
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell1") as! MenuTableCell
cell.lblCategoryTitle.text = arrayMenuCat[indexPath.row].category_name
cell.menuProductsAPI(categoryid: arrayMenuCat[indexPath.row].id)
return cell
}
And remove menuProductsAPI(categoryid: catgID!) from awakeFromNib method

UISearchBar results stored in an Array and displayed in a UITableView are messing with my didSelectRowAt indexPath method (Swift)

I have a UITableView that is populated with items from a titles array and I have it setup so that when didSelectRowAt indexPath is called, a variable called arrayIndex is changed to the indexPath and the content of the next VC is changed.
So if a user taps on:
Row 0 > VC will have Title 0, Definition 0 and Link 0
Row 12 > VC will have Title 12, Definition 12 and Link 12
I have a search bar however that stores the filtered results in a searchResults array and displays them in the tableView. When a search is performed, the array index will no longer correspond, so if the search query changes the tableview to
Title 4 on Row 0 > VC will have Title 0, Definition 0 and Link 0
Title 5 on Row 1 > VC will have Title 1, Definition 1 and Link 1
Title 18 on Row 2 > VC will have Title 2, Definition 2 and Link 2
I understand why it doesn't work as expected, but I am not sure how to update my logic to fix it. Thoughts? Here is my code:
ListController:
import UIKit
var arrayIndex = 0 // is used in DefinitionController to determine which title/definition/link to show.
var isSearching = false
class ListController: UIViewController, UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate {
#IBOutlet var tableView: UITableView!
#IBOutlet var searchBar: UISearchBar!
// Search Delegate
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText == "" {
isSearching = false
tableView.reloadData()
} else {
isSearching = true
searchResults = (titles.filter { $0.lowercased().contains(searchText.lowercased()) })
tableView.reloadData()
}
}
//Table Delegate
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if isSearching == true {
// code to run if searching is true
} else {
arrayIndex = indexPath.row // assigns the value of the selected tow to arrayIndex
}
performSegue(withIdentifier: "segue", sender: self)
tableView.deselectRow(at: indexPath, animated: true)
}
// Table Data Source
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if isSearching == true {
return searchResults.count
} else {
return titles.count
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Cell Data Source
let cell = UITableViewCell()
if isSearching == true {
cell.textLabel?.text = searchResults[indexPath.row]
} else {
cell.textLabel?.text = titles[indexPath.row]
}
// Cell Visual Formatting
cell.backgroundColor = UIColor(red:0.05, green:0.05, blue:0.07, alpha:0)
cell.textLabel?.textColor = UIColor.white
cell.textLabel?.font = UIFont(name: "Raleway", size: 18)
cell.accessoryType = UITableViewCellAccessoryType.disclosureIndicator
// if (cell.isSelected) {
// cell.backgroundColor = UIColor.cyan
// }else{
// cell.backgroundColor = UIColor.blue
// }
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "\(titles.count) Definitions"
// TextField Color Customization
let searchBarStyle = searchBar.value(forKey: "searchField") as? UITextField
searchBarStyle?.textColor = UIColor.white
searchBarStyle?.backgroundColor = UIColor(red:1.00, green:1.00, blue:1.00, alpha:0.05)
}
}
Definition Controller:
import UIKit
class DefinitionController: UIViewController {
#IBOutlet var definitionTitle: UILabel!
#IBOutlet var definitionBody: UILabel!
#IBOutlet var definitionSources: UILabel!
// Open link in Safari
#objc func tapFunction(sender:UITapGestureRecognizer) {
print("tap working")
if let url = URL(string: "\(links[arrayIndex])") {
UIApplication.shared.openURL(url)
}
}
override func viewDidLoad() {
super.viewDidLoad()
definitionTitle.text = titles[arrayIndex]
definitionBody.text = definitions[arrayIndex]
self.title = "" // Used to be \(titles[arrayIndex])
// Sources Link
let tap = UITapGestureRecognizer(target: self, action: #selector(DefinitionController.tapFunction))
definitionSources.addGestureRecognizer(tap)
}
}
Try using a dictionary where the key is your title and its value its a dictionary containing the definition and link, and an array where you will store the search results i.e the keys searched.
var dictionary = ["title 0":["definition 0", "Link 0"], "title 1": ["definition 1", "Link 1"]]
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText == "" {
isSearching = false
tableView.reloadData()
} else {
isSearching = true
for (key, value) in dictionary {
if key==searchText{
resultsArray.append(key)
}
}
tableView.reloadData()
}
}
Now when you tap on a cell in the List Controller let it know which key's details you want to initialise and load in the next VC:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let DefinitionViewController = self.storyboard?.instantiateViewController(withIdentifier: "DefinitionViewController") as! DefinitionViewController
//initialise data for the view controller
ListViewController.initDetails(forKey: resultsArray[indexPath.row])
performSegue(withIdentifier: "segue", sender: self)
tableView.deselectRow(at: indexPath, animated: true)
}
In your Definition Controller initialise the details:
func initDetails(forKey key: String) {
definitionBody.text=dictionary[key]![0]
definitionSources.text=dictionary[key]![1]
}
I thought of what seems to me like a pretty dirty solution, because it requires keeping two sets of titles, so I'm still curious if anyone knows a better way, but this does work:
If searching (to avoid calling the switch if it's not needed), under didSelectRowAt indexPath, I created a switch that essentially checks the text of the selected cell and sets the value of arrayIndex accordingly.
let selectedCell = tableView.cellForRow(at: indexPath)?.textLabel!.text ?? "Undefined"
switch selectedCell {
case "Anger": arrayIndex = 0
case "Anguish": arrayIndex = 1
case "Anxiety": arrayIndex = 2
case "Annoyance": arrayIndex = 3
case "Apathy": arrayIndex = 4
default: print("Undefined Search Query")
}
The titles array will eventually have some 55 elements and I had hoped to keep all the data in a separate Data.swift file, but this is the only solution I have so far.

Adding items into Objects

I'm looking to be able to append a personal location into the MKLocationSearchCompletion array that will can be found when the user searches through the search bar. However, I am having trouble understanding how items are stored into objects and whether I can add a placemark object (or location information) into the MKLocationSearch object. What I've been able to garner from the documentation is that the MKLocalSearchCompleter object stores strings that are accessed when the user types in partial strings into the search bar. But I am not sure where I can access this array and add new locations.
Here is how the code is structured to display search completion results:
var searchCompleter = MKLocalSearchCompleter()
var searchResults = [MKLocalSearchCompletion]()
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
searchCompleter.delegate = self
searchBar.delegate = self
}
extension ViewController: MKLocalSearchCompleterDelegate {
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
searchResults = completer.results
searchResultsTableView.reloadData()
}
func completer(_ completer: MKLocalSearchCompleter, didFailWithError error: Error) {
// handle error
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchResults.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let searchResult = searchResults[indexPath.row]
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
cell.textLabel?.attributedText = highlightedText(searchResult.title, inRanges: searchResult.titleHighlightRanges, size: 17.0)
cell.detailTextLabel?.attributedText = highlightedText(searchResult.subtitle, inRanges: searchResult.subtitleHighlightRanges, size: 12.0)
return cell
}
}
extension ViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchCompleter.queryFragment = searchText
}
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
self.searchBar.endEditing(true)
searchBar.resignFirstResponder()
return true
}
}
I don't think that you can add your own locations and POIs to MapKit, but:
1) I would suggest you create an own enum
class CustomSearchResult {
let title: String
...
}
enum SearchResultType {
case localSearchResult(result: MKLocalSearchCompletion)
case customResult(result: CustomSearchResult)
}
2) And you have your array of results:
var searchResults = [SearchResultType]()
3) In completerDidUpdateResults you can add your personal results and the MapKit results into your searchResults array:
searchResults = completer.results.map {
SearchResultType.localSearchResult(result: $0) }
// Add here custom results
searchResults.append(SearchResultType.customResult(result:
CustomSearchResult(title: "test")))
4) ..and in cellForRowAtIndexPath you can decide whether you have custom or MapKit result:
let searchResult = searchResults[indexPath.row]
switch searchResult {
case .customResult(let result):
cell.textLabel.text = result.title
case .localSearchResult(let result):
cell.textLabel.text = result.title
}

Swift: How can I get the records from the database according to the cell pressed

Is it possible to get the data from the external database when a UItableViewCell is pressed?
I managed to create a UItableView where I am displaying the data from the database. If I press a cell then all the data that are linked to it should be displayed. For eg. if I have 4 main categories in the database such as TOOLS, OTHERS, SECURITY, PETS and each of them has its sub-catecory and are linked with each other in the database. So if I click on Pets, it should filter out and only Show me CATS, DOGS, COWS, LIONS. When I run this SQL I am able to get the information but cant figure it this out on Swift.
UItableViewCell is in my FirstviewController and its the Main Category .
When I click here it goes to my destination VC and has the table again in here.enter image description here
DestViewController is the sub-category
enter image description here
My CategoryList_ViewController.swift
import Foundation
import UIKit
import WebKit
class CategoryList_ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBAction func refresh(sender: AnyObject) {
get()
}
var values:NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
get();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func get(){
let url = NSURL(string: "c:\deskstop\mobiletec\assignment\assignment2\cat.php")
let data = NSData(contentsOfURL: url!)
values = try! NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSArray
tableView.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! CategoryList_TableViewCell
let maindata = values[indexPath.row]
cell.categoryLabel.text = maindata["NAME"] as? String
return cell;
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "catView" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let value = values[indexPath.row]
let controller = segue.destinationViewController as! SubCatergory_ViewController
controller.cate_Id = value["id"] as! String
controller.catTitleRec = value["NAME"] as! String
}
}
}
}
my SubCatergory_ViewController.swift
import Foundation
import UIKit
import WebKit
class SubCatergory_ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var caID: UILabel!
#IBOutlet weak var catTitle_Label: UILabel!
#IBAction func refresh(sender: AnyObject) {
get()
}
var values:NSArray = []
var catTitleRec = ""
var cate_Id = ""
override func viewDidLoad() {
super.viewDidLoad()
catTitle_Label.text = catTitleRec
caID.text = cate_Id
get();
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func get(){
let request = NSMutableURLRequest(URL: NSURL(string: "c:\deskstop\mobiletec\assignment\assignment2\subcat.php")!)
request.HTTPMethod = "GET"
let postString = "a=\(cate_Id)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
print("response = \(response)")
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! subCateListTableViewCell
let maindata = values[indexPath.row]
cell.categoryLabel.text = maindata["NAME"] as? String
return cell;
}
}
and my subcat.php
<?php
$connection = mysql_connect(........);
$catefilter = $_GET['a'];
if(!$connection){
die('Connection Failed');
}
else{
$dbconnect = #mysql_select_db($database_UNIASSIGNMENT, $connection);
if(!$dbconnect){
die('Could not connect to Database');
}
else{
$query = 'SELECT category_group.group_id , category.NAME FROM category_group LEFT JOIN category ON category.id = category_group.category_id WHERE category_group.group_id =' . $catefilter ;
$resultset = mysql_query($query, $connection);
$records= array();
while($r = mysql_fetch_assoc($resultset)){
$records[] = $r;
}
echo json_encode($records);
}
}
?>
My first VC works fine but my second VC doesnot get the data
Thanks for your time :)
SK
To access the cell that has been pressed, you need to call the didSelectRowAtIndexPath function.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let value = values[indexPath.row]
let vc = storyboard?.instantiateViewController(withIdentifier: "SubCatergory_ViewController") as! SubCatergory_ViewController
vc.cate_Id = value["NAME"] as! String
//self.navigationController?.pushViewController(vc, animated: true)
self.present(vc, animated: true, completion: nil)
}
First you get the value out of your values Array on the indexPark.row. Then you instantiate your second viewController.
Then you set your String value of cate_Id to the desired String value of your item value. And then you just need to present the new viewController.
If you're using a UINavigationController and you want a "back" button, then you use: self.navigationController?.pushViewController(vc, animated: true)
If you just want to present the viewController, you use self.present(vc, animated: true, completion: nil)
Comment or uncomment whatever presentation method you prefer.

Error subscript

I got that error a while ago and I'm not sure, what's wrong. The Post is just normal custom class with two attributes of type String and int.
web api :http://jsonplaceholder.typicode.com/posts
PostService :
class PostService {
var settings:Settings!
init(){
self.settings = Settings()
}
func getPosts(callback:(NSArray) ->()){
request(settings.viewPost, callback: callback)
}
func request(url:String , callback:(NSArray) ->() ){
let nsURL = NSURL(string: url)
let task = NSURLSession.sharedSession().dataTaskWithURL(nsURL!){(data , repsonse , error) in
//var error:NSError?
do {
let response = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers) as! NSArray
callback(response)
} catch {
print(error)
}
}
task.resume()
}
}
settings :
import Foundation
class Settings {
var viewPost = "http://jsonplaceholder.typicode.com/posts"
}
post:
class Post {
var _userId:Int
var _title: String
init(userid:Int , title:String){
self._userId = userid
self._title = title
}
func toJSON() ->String{
return ""
}
}
and tableViewController:
class TableViewController: UITableViewController {
var postsCollection = [Post]()
var service:PostService!
override func viewDidLoad() {
super.viewDidLoad()
service = PostService()
service.getPosts{
(response) in
self.loadPosts(response[" "] as! NSArray )
}
}
func loadPosts(posts:NSArray){
for post in posts{
var userId = post["userId"] as! Int
var title = post["title"] as! String
let postObj = Post(userid: userId, title: title)
postsCollection.append(postObj)
dispatch_async(dispatch_get_main_queue()){
self.tableView.reloadData()
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 0
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return postsCollection.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let post = postsCollection[indexPath.row] as NSData
cell.textLabel?.text = post._userId
cell.detailTextLabel = post._title
return cell
}
why error Cannot subscript a value of type '[Post]' in line
I'm not sure that this is the issue but it is an issue.
Since postsCollection has a distinct type there is no need to cast the type.
NSData is the wrong type anyway.
let post = postsCollection[indexPath.row] // the compiler infers to Post
Side note: Put the dispatch block to reload the table view after the repeat loop to create the Post instances. Reloading the table view in each iteration of the loop is very expensive and not necessary.
for post in posts {
...
}
dispatch_async(dispatch_get_main_queue()){
self.tableView.reloadData()
}
And (public) properties starting with a underscore are pretty unusual (in Swift).
PS: There are two further issues
cell.textLabel?.text = String(post._userId)
cell.detailTextLabel?.text = post._title
Edit: Simple working solution, there are only two classes
class Post
class Post : CustomStringConvertible {
var userId:Int
var title: String
init(userid:Int , title:String){
self.userId = userid
self.title = title
}
var description : String { return String(userId) }
}
class TableViewController
class TableViewController: UITableViewController {
var postsCollection = [Post]()
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "http://jsonplaceholder.typicode.com/posts")
NSURLSession.sharedSession().dataTaskWithURL(url!){ [unowned self] (data , repsonse , error) in
if error != nil {
print(error!)
} else {
do {
let posts = try NSJSONSerialization.JSONObjectWithData(data!, options:NSJSONReadingOptions.MutableContainers) as! [[String:AnyObject]]
for post in posts {
let postObj = Post(userid: post["userId"] as! Int, title: post["title"] as! String)
self.postsCollection.append(postObj)
}
dispatch_async(dispatch_get_main_queue()){
self.tableView.reloadData()
}
} catch let error as NSError {
print(error)
}
}
}.resume()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 }
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return postsCollection.count }
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let post = postsCollection[indexPath.row]
cell.textLabel!.text = String(post.userId)
cell.detailTextLabel!.text = post.title
return cell
}
}

Resources