I'm creating an app for iOS that get data from my server with json and store it on a tableview; with this no problems, my data are simple notes, some notes are linked together forming projects (simple dependency_id on my database sql), my question is: How can i group my notes by project, like a contact list? (ex. http://img.wonderhowto.com/img/13/66/63535060544981/0/siri-exploit-you-could-bypass-iphones-lock-screen-call-message-any-contact-ios-7-1-1.w654.jpg)
This is the source that populate the table with all notes:
//
// TableController.swift
// uitableview_load_data_from_json
import UIKit
class TableController: UITableViewController {
var TableData:Array< String > = Array < String >()
var userid = NSUserDefaults.standardUserDefaults().stringForKey("userid")!
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("http:/localhost/index.php/iOS_getNomenTasks?n=" + userid)
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = TableData[indexPath.row]
return cell
}
func get_data_from_url(url:String)
{
let httpMethod = "GET"
let timeout = 15
let url = NSURL(string: url)
let urlRequest = NSMutableURLRequest(URL: url!,
cachePolicy: .ReloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 15.0)
let queue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(
urlRequest,
queue: queue,
completionHandler: {(response: NSURLResponse!,
data: NSData!,
error: NSError!) in
if data.length > 0 && error == nil{
let json = NSString(data: data, encoding: NSASCIIStringEncoding)
self.extract_json(json!)
}else if data.length == 0 && error == nil{
println("Nothing was downloaded")
} else if error != nil{
println("Error happened = \(error)")
}
}
)
}
func extract_json(data:NSString)
{
var parseError: NSError?
let jsonData:NSData = data.dataUsingEncoding(NSASCIIStringEncoding)!
let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &parseError)
if (parseError == nil)
{
if let task_list = json as? NSArray
{
for (var i = 0; i < task_list.count ; i++ )
{
if let tasj_obj = task_list[i] as? NSDictionary
{
if let task_id = tasj_obj["id"] as? String
{
if let task_name = tasj_obj["tk_title"] as? String
{
if let task_type = tasj_obj["tk_type"] as? String
{
TableData.append(task_name)
}
}
}
}
}
}
}
do_table_refresh();
}
func do_table_refresh()
{
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
}
ok..
task_id is the note id,
task_name is the note name,
task_type is the value that identify if note is a project or not, if task_type is 0, the note is a simple note, if task_type is 1 the note is a project.
If you create an UITableViewController, you have the function :
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
With it, you have 3 sections who contains 2 lines :
var tab: [String] = ["section 1", "section 2", "section 3"]
var tabData: [AnyObject] = [["item1", "item2"],["item1", "item2"],["item1", "item2"]]
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return tab.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataTab[section].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell = UITableViewCell()
return cell
}
Related
I'm working with CocktailDB.
By creating a request I get a JSON file, parse it with Decodable protocol. From JSON I get all drinks' categories and display them as the sections of my tableview.
In each tableview section I want to display drinks from specific category (section's header). One drink per section cell from the category (drink's strDrink (name) and strDrinkThumb (image)).
I have a method that creates a request to get drinks from specific category - getDrinksFrom(category: String).
Please advice how can I call this method for specific section to get and display drinks from specific category in this section?
My code:
class ViewController: UIViewController {
var drinks = [Drink]()
var categories = [Category]()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
getCategories()
getDrinksFrom(category: "Cocoa")
}
func getCategories() {
let url = URL(string: "https://www.thecocktaildb.com/api/json/v1/1/list.php?c=list")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error == nil {
do {
self.categories = try JSONDecoder().decode(Categories.self, from: data!).drinks
DispatchQueue.main.async {
self.tableView.reloadData()
}
print(self.categories)
} catch {
print(error)
}
}
}.resume()
}
func getDrinksFrom(category: String) {
let url = URL(string: "https://www.thecocktaildb.com/api/json/v1/1/filter.php?c=\(category)")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if error == nil {
do {
self.drinks = try JSONDecoder().decode(Drinks.self, from: data!).drinks
DispatchQueue.main.async {
self.tableView.reloadData()
}
print(self.drinks)
} catch {
print(error)
}
}
}.resume()
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return categories.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return categories[section].strCategory
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "drinkCell") as! DrinkCell
cell.drinkName.text = drinks[indexPath.row].strDrink
let url = drinks[indexPath.row].strDrinkThumb
cell.drinkImage.downloaded(from: url)
return cell
}
}
// to download an image from web
extension UIImageView {
func downloaded(from url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() { [weak self] in
self?.image = image
}
}.resume()
}
func downloaded(from link: String, contentMode mode: UIView.ContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
downloaded(from: url, contentMode: mode)
}
}
Category Model:
struct Categories:Decodable {
var drinks: [Category]
}
struct Category:Decodable {
var strCategory: String
}
Drink Model:
struct Drinks:Decodable {
var drinks: [Drink]
}
struct Drink:Decodable {
var strDrink: String
var strDrinkThumb: String
}
What I have for know:
JSON structure:
My suggestion is to create a custom struct Category with name and drinks for the sections. It does not conform to Decodable, this is intended
struct Category {
let name : String
var drinks : [Drink]
}
and an appropriate data source array
var categories = [Category]()
then load and parse the categories with traditional JSONSerialization and populate the array by mapping the names. Further add a completion handler
func getCategories(completion: #escaping () -> Void) {
let url = URL(string: "https://www.thecocktaildb.com/api/json/v1/1/list.php?c=list")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if let error = error { print(error); return }
do {
let result = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
let categoryNames = result["drinks"] as! [[String:String]]
self.categories = categoryNames.map{ Category(name: $0["strCategory"]!, drinks:[])}
completion()
} catch {
print(error)
}
}.resume()
}
To avoid naming confusion (too many drinks) name the root struct Response
struct Response : Decodable {
let drinks: [Drink]
}
Load the data related to a category and assign the drinks array to the corresponding array in categories
func getDrinksFrom(category: String) {
let url = URL(string: "https://www.thecocktaildb.com/api/json/v1/1/filter.php?c=\(category)")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if let error = error { print(error); return }
do {
let drinks = try JSONDecoder().decode(Response.self, from: data!).drinks
guard let index = categories.firstIndex(where: {$0.name == category}) else { return }
self.categories[index].drinks = drinks
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch {
print(error)
}
}.resume()
}
and replace viewDidLoad with
override func viewDidLoad() {
super.viewDidLoad()
getCategories { [weak self] in
self?.getDrinksFrom(category: "Cocoa")
}
}
Finally change the table view data source methods to match the section structure
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return categories.count
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return categories[section].name
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return categories[section].drinks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "drinkCell") as! DrinkCell
let category = categories[indexPath.section]
let drink = category.drinks[indexPath.row]
cell.drinkName.text = drink.strDrink
let url = drink.strDrinkThumb
cell.drinkImage.downloaded(from: url)
return cell
}
}
You can also put both functions together and load all drinks for all categories
func loadAllCategories() {
let url = URL(string: "https://www.thecocktaildb.com/api/json/v1/1/list.php?c=list")
URLSession.shared.dataTask(with: url!) { (data, response, error) in
if let error = error { print(error); return }
do {
let result = try JSONSerialization.jsonObject(with: data!) as! [String:Any]
let categoryNames = (result["drinks"] as! [[String:String]]).map{$0["strCategory"]!}
let group = DispatchGroup()
for category in categoryNames {
let categoryURLString = "https://www.thecocktaildb.com/api/json/v1/1/filter.php?c=\(category)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
let categoryURL = URL(string: categoryURLString)!
group.enter()
let categoryTask = URLSession.shared.dataTask(with: categoryURL) { (categoryData, _, categoryError) in
defer { group.leave() }
if let categoryError = categoryError { print(categoryError); return }
do {
let drinks = try JSONDecoder().decode(Response.self, from: categoryData!).drinks
self.categories.append(Category(name: category, drinks: drinks))
} catch {
print(error)
}
}
categoryTask.resume()
}
group.notify(queue: .main) {
self.tableView.reloadData()
}
} catch {
print(error)
}
}.resume()
}
This is just a pseudocode, which will give you an idea how you can proceed further. The code has not been tested.
Create an array of sections to be loaded.
var sections: [Sections] = []
In you tableview delegates you can create a struct for the sections that you need to load, which will help you to identify the section in cell for row index path where you can call API based on categories.
extension ViewController: UITableViewDataSource, UITableViewDelegate {
struct Sections {
static var count = 0
// In stantiate table view headers index order
enum SectionType {
case SoftDrink
case OrdinaryDrink
case MilkShake
}
var type: SectionType?
var section: Int?
var rows: Int?
}
func setUpTableView() {
// Set Up Tableview Data
if check if Drink is type of SoftDrink /*If you sections are loaded dynamic u can add condition*/ {
sections.append(Sections(type: .SoftDrink, section: Sections.count, rows: 1))
Sections.count += 1
}
Sections.count = 0
}
func numberOfSections(in _: UITableView) -> Int {
sections.count
}
func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
sections[section].rows ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var tableCell: UITableViewCell = UITableViewCell()
guard let type = sections[indexPath.section].type else {
tableCell.selectionStyle = .none
return tableCell
}
switch type {
case .SoftDrink: break
// Instantiate cell and API calls.
case .OrdinaryDrink: break
// Instantiate cell and API calls.
case .MilkShake: break
// Instantiate cell and API calls.
}
tableCell.selectionStyle = .none
return tableCell
}
}
setUpTableView() can be called in viewDidLoad Method.
I already new in swift 3 and objetive c, right now I am stuck into how can I pass the id of each row to another table view controller when the user tap in the row the user want to go.
Here is the json data firstFile:
[
{"id_categoria":"1","totalRows":"323","nombre_categoria":"Cirug\u00eda"},
{"id_categoria":"2","totalRows":"312","nombre_categoria":"Med Interna"},
{"id_categoria":"3","totalRows":"6","nombre_categoria":"Anatomia"},
{"id_categoria":"4","totalRows":"24","nombre_categoria":"Anestesiologia"},
...]
Here is my first table view controller:
import UIKit
class CatMedVC: UIViewController, UITableViewDataSource {
#IBAction func volver(_ sender: Any) { }
#IBOutlet weak var listaCategoria: UITableView!
var fetchedCategoria = [Categoria]()
override func viewDidLoad() {
super.viewDidLoad()
listaCategoria.dataSource = self
parseData()
}
override var prefersStatusBarHidden: Bool{
return true
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedCategoria.count
}
public func tableView(_ tableView: UITableView, cellForRowAt IndexPath: IndexPath) ->
UITableViewCell {
let cell = listaCategoria.dequeueReusableCell(withIdentifier: "cell")
cell?.textLabel?.text = fetchedCategoria[IndexPath.row].esp
cell?.detailTextLabel?.text = fetchedCategoria [IndexPath.row].totalRows
return cell!
}
func parseData() {
let url = "http://www.url.com/firstFile.php" //in json format
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "GET"
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: request) { (data, response, error) in
if(error != nil) {
print("Error")
}
else {
do {
let fetchedData = try JSONSerialization.jsonObject(with:data!, options: .mutableLeaves) as! NSArray
//print(fetchedData)
for eachFetchedCategoria in fetchedData {
let eachCategoria = eachFetchedCategoria as! [String : Any]
let nombre_categoria = eachCategoria["nombre_categoria"] as! String
let totalRows = eachCategoria["totalRows"] as! String
let id_categoria = eachCategoria["id_categoria"] as! String
self.fetchedCategoria.append(Categoria(nombre_categoria: nombre_categoria, totalRows: totalRows, id_categoria: id_categoria))
}
//print(self.fetchedCategoria)
self.listaCategoria.reloadData()
}
catch {
print("Error 2")
}
}
}
task.resume()
}
}
class Categoria {
var nombre_categoria : String
var totalRows : String
var id_categoria : String
init(nombre_categoria : String, totalRows : String, id_categoria : String) {
self.nombre_categoria = nombre_categoria
self.totalRows = totalRows
self.id_categoria = id_categoria
}
}
So I need pass the id_categoria String into the another table view to show the data for the id selected previously...here I don't know how to do it...I have the json file waiting for the id selected previously..but I don't know how to catch it into the url
Here the second table view:
import UIKit
class EspMedVC: UITableViewController {
var TableData:Array< String > = Array < String >()
var EspecialidadArray = [String]()
#IBAction func volver(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("http://www.url.com/secondFile.php?id=") // Here I need to put the id_categoria String in json format
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
cell.textLabel?.text = TableData[indexPath.row]
return cell
}
func get_data_from_url(_ link:String)
{
let url:URL = URL(string: link)!
let session = URLSession.shared
let request = NSMutableURLRequest(url: url)
request.httpMethod = "GET"
request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData
let task = session.dataTask(with: request as URLRequest, completionHandler: {
(
data, response, error) in
guard let _:Data = data, let _:URLResponse = response , error == nil else {
return
}
self.extract_json(data!)
})
task.resume()
}
func extract_json(_ data: Data)
{
let json: Any?
do
{
json = try JSONSerialization.jsonObject(with: data, options: [])
}
catch
{
return
}
guard let data_list = json as? NSArray else
{
return
}
if let nombre_especialidad = json as? NSArray
{
for i in 0 ..< data_list.count
{
if let nombre_esp_obj = nombre_especialidad[i] as? NSDictionary
{
if let nombre_especialidad = nombre_esp_obj["subesp"] as? String
{
if let totalRows = nombre_esp_obj["totalRows"] as? String
{
TableData.append(nombre_especialidad + " [" + totalRows + "]")
}
}
}
}
}
DispatchQueue.main.async(execute: {self.do_table_refresh()})
}
func do_table_refresh()
{
self.tableView.reloadData()
}
}
This is a rough guide, please search for the methods in the documentation or here at other questions inside stackoverflow.
1) Add a variable inside your EspMedVC that will hold the "id_categoria String" that should be displayed.
2) Add a variable inside your CatMedVC that will hold the "id_categoria String" that the user selected.
3) Implement the "didSelectRow" delegate method from your tableview inside the "CatMedVC", inside this method you should set the variable set on step 2.
4) Implement the "prepareForSegue" method inside your CatMedVC, inside the the implementation you should retrieve the destination VC, cast it to "EspMedVC" and set the variable from step 1.
5) On the "viewDidLoad" from EspMedVC you can now use the variable set on step 2 to query your JSON and update the table view accordingly.
I got an error in self.tableView.reloadData(). Can it be because I use the SSASideMenu lib, where there are no segues between the menu and other views? To me, it seems like my tableView was not initialized.
class GroupListViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var TableData:Array< String > = Array < String >()
#IBOutlet var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("http://www.kaleidosblog.com/tutorial/tutorial.json")
title = "title"
var menuImage:UIImage = UIImage(named: "sidebtn")!
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "1", style: .Plain, target: self, action: "presentLeftMenuViewController")
menuImage = menuImage.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
self.navigationItem.leftBarButtonItem?.image = menuImage
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = TableData[indexPath.row]
return cell
}
func get_data_from_url(url:String)
{
let httpMethod = "GET"
let timeout = 15
let url = NSURL(string: url)
let urlRequest = NSMutableURLRequest(URL: url!,
cachePolicy: .ReloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 15.0)
let queue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(
urlRequest,
queue: queue,
completionHandler: {(response: NSURLResponse!,
data: NSData!,
error: NSError!) in
if data.length > 0 && error == nil{
let json = NSString(data: data, encoding: NSASCIIStringEncoding)
self.extract_json(json!)
}else if data.length == 0 && error == nil{
println("Nothing was downloaded")
} else if error != nil{
println("Error happened = \(error)")
}
}
)
}
func extract_json(data:NSString)
{
var parseError: NSError?
let jsonData:NSData? = data.dataUsingEncoding(NSASCIIStringEncoding)!
let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(jsonData!, options: nil, error: &parseError)
if (parseError == nil)
{
if let countries_list = json as? NSArray
{
for (var i = 0; i < countries_list.count ; i++ )
{
if let country_obj = countries_list[i] as? NSDictionary
{
if let country_name = country_obj["country"] as? String
{
if let country_code = country_obj["code"] as? String
{
TableData.append(country_name + " [" + country_code + "]")
}
}
}
}
}
}
do_table_refresh();
}
func do_table_refresh()
{
self.tableView.reloadData()
}
Ok. The exception you are getting is because your tableView is nil after viewdidLoad. It can be a connection problem, so first try this answer:
IBOutlet UITableView is null after View did load
Second, if all your nibs and are proper and you are still seeing this error. Then try the below code. [put tableview frame as you want]. This does everything you want to do programmatically and will work.
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var TableData:Array< String > = Array < String >()
var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("http://www.kaleidosblog.com/tutorial/tutorial.json")
tableView = UITableView(frame: self.view.frame)
title = "title"
var menuImage:UIImage = UIImage(named: "sidebtn")!
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "1", style: .Plain, target: self, action: "presentLeftMenuViewController")
menuImage = menuImage.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
self.navigationItem.leftBarButtonItem?.image = menuImage
self.view.addSubView(tableView)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = TableData[indexPath.row]
return cell
}
func get_data_from_url(url:String)
{
let httpMethod = "GET"
let timeout = 15
let url = NSURL(string: url)
let urlRequest = NSMutableURLRequest(URL: url!,
cachePolicy: .ReloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 15.0)
let queue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(
urlRequest,
queue: queue,
completionHandler: {(response: NSURLResponse!,
data: NSData!,
error: NSError!) in
if data.length > 0 && error == nil{
let json = NSString(data: data, encoding: NSASCIIStringEncoding)
self.extract_json(json!)
}else if data.length == 0 && error == nil{
println("Nothing was downloaded")
} else if error != nil{
println("Error happened = \(error)")
}
}
)
}
func extract_json(data:NSString)
{
var parseError: NSError?
let jsonData:NSData? = data.dataUsingEncoding(NSASCIIStringEncoding)!
let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(jsonData!, options: nil, error: &parseError)
if (parseError == nil)
{
if let countries_list = json as? NSArray
{
for (var i = 0; i < countries_list.count ; i++ )
{
if let country_obj = countries_list[i] as? NSDictionary
{
if let country_name = country_obj["country"] as? String
{
if let country_code = country_obj["code"] as? String
{
TableData.append(country_name + " [" + country_code + "]")
}
}
}
}
}
}
do_table_refresh();
}
func do_table_refresh()
{
self.tableView.reloadData()
}
}
In storyboard, find your tableviewcontroller, and right click on the tableview to check the referencing outlets, there are big chances under the referencing outlets, your defined your tableview variable not the same as the one you defined in your codes.
Then you just need to delete the referencing outlets of the tableview, also delete the codes "var tableView: UITableView!", then re-contorl drag the tableview to your code to make a new reference. It happened to me once for this reason.
I've been trying to return string urls from JSON and store it in array and then show the array in UITableView. but it shows empty UILabel.
class PhotosTableViewController: UITableViewController {
let imageLoadURL = "https://..."
var TAG_IMG_URL = []
verride func viewDidLoad() {
super.viewDidLoad()
getLatestPhotos()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TAG_IMG_URL.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! KivaLoanTableViewCell
cell.nameLabel.text = TAG_IMG_URL[indexPath.row] as? String
return cell
}
func getLatestPhotos() {
let request = NSURLRequest(URL: NSURL(string: imageLoadURL)!)
let urlSession = NSURLSession.sharedSession()
let task = urlSession.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
if error != nil {
println(error.localizedDescription)
}
self.TAG_IMG_URL = self.parseJsonData(data)
println("\(self.TAG_IMG_URL.count)")
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
})
task.resume()
}
func parseJsonData(data: NSData) -> NSArray {
var error:NSError?
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as? NSDictionary
if error != nil {
println(error?.localizedDescription)
}
if let j = jsonResult, let mediaObjects = j.valueForKeyPath("feed.entry.media$group.media$content") as? NSArray {
if let imageUrls: AnyObject = mediaObjects.valueForKey("url") {
TAG_IMG_URL = imageUrls as! NSArray
}
}
println("\(TAG_IMG_URL)")
self.alert.dismissWithClickedButtonIndex(0, animated: true)
return TAG_IMG_URL
}
}
During parseJsonData it returns the urls which it look like (below), but when i try to show it in the UITableView it always becomes empty UILabel so what am i doing wrong here ?:
(
(
"https://..."
),
(
"https://..."
)
)
Note : in numberOfRowsInSection it returns the right amount which its 2 urls.
Try this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! KivaLoanTableViewCell
cell.nameLabel.text = TAG_IMG_URL[indexPath.row][0] as? String
return cell
}
The problem that you have 2-dimensional array, so you should get first object in object:
TAG_IMG_URL[indexPath.row].firstObject or TAG_IMG_URL[indexPath.row][0].
I have trouble in loading the table view when parsing json files in swift.
Parsing the data is doing well. But no data are displayed in the table view.
This is the code :
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var redditListTableView: UITableView!
var tableData = []
#IBAction func cancel(sender: AnyObject) {
self.dismissViewControllerAnimated(false, completion: nil)
println("cancel")
}
#IBAction func done(sender: AnyObject) {
println("done")
}
override func viewDidLoad() {
super.viewDidLoad()
searchJsonFile("blabla.json")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
println(tableData.count)
return tableData.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
let rowData: NSString = self.tableData[indexPath.row] as NSString
cell.textLabel.text = rowData as String
return cell
}
func searchJsonFile(searchFile: String) {
let urlPath = "http://data.../\(searchFile)"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
println("Task completed")
if(error != nil) {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if(err != nil) {
println("JSON Error \(err!.localizedDescription)")
}
var results = [String]()
if let results1 = jsonResult["data"] as? NSDictionary{
for (key, value) in results1 {
if let eng = value["eng"] as? NSDictionary {
if let name = eng["name"] as? NSString{
results.append(name)
}
}
}
}
//println(results) OK!!!!
dispatch_async(dispatch_get_main_queue(), {
self.tableData = results
self.redditListTableView.reloadData()
})
})
task.resume()
}
}
You are returning 0 from numberOfSectionsInTableView - so you get no data displayed. You want 1 section -
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
If you are not having sections then just remove this function or comment
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 0
}
or else return 1