Why my Collectionview cells are not showing when i move from that viewcontroller in swift? - json

I am able to parse JSON and adding cells in Collectionview.. but if i move from this Viewcontroller and coming to viewcontroller then collectionview is not showing.. but added data in JSON
code for adding collectionview and JSON parsing:
class ImageItemModel{
var title: String?
var profileImage: UIImage?
var pic_id: Double?
init(title: String?, imgTitle: UIImage?, pic_id: Double?) {
self.title = title
self.profileImage = imgTitle
self.pic_id = pic_id
}
}
class EditProfileImageViewController: UIViewController {
#IBOutlet weak var titleTextfield: UITextField!
private var imageProfile : UIImage?
private var imagePicker : EasyImagePicker?
#IBOutlet weak var collectionView: UICollectionView!
var arrImageItems = [ImageItemModel]()
#IBAction func imgtitleSaveBtn(_ sender: Any) {
postServiceCall()
}
fileprivate func postServiceCall(){
if titleTextfield.text?.trim() == ""{
return self.view.makeToast("please add service title")
}
let parameters = ["image_title" : titleTextfield.text?.trim() ?? ""]
APIReqeustManager.sharedInstance.uploadMultipartFormData(param: parameters, url: CommonUrl.edit_profile_images, image: imageProfile, fileName: "image", vc: self, isHeaderNeeded: true) {(responseData) in
print("edit profile result \(responseData)")
if let result = responseData.dict?["result"] as? NSDictionary{
let success = result["status"] as? [String : Any]
let message = success?["message"] as? String
if message == "Success"{
let image = result["image"] as? [String : Any]
let picId = image?["id"]
self.arrImageItems.append(ImageItemModel(title: self.titleTextfield.text, imgTitle: self.imageProfile, pic_id: picId as! Double))
self.collectionView.reloadData()
}
else{
self.view.makeToast(CommonMessages.somethingWentWrong)
}
}
}
}
extension EditProfileImageViewController : UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrImageItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as! ImageCollectionViewCell
cell.imgView.image = arrImageItems[indexPath.item].profileImage
cell.lblTitle.text = arrImageItems[indexPath.row].title
cell.deleteButton.tag = indexPath.row
cell.deleteButton.addTarget(self, action: #selector(deleteService(sender:)), for: UIControl.Event.touchUpInside)
return cell
}
}
with the above code i am able to add collectionview cells and able to store data in JSON but.. if i move from this viewcontroller and coming back to this viewcontroller then collectionview is not showing, why? whats wrong? please do help me with code.. i got stuck here from long time.

There are couple of issues that you should fix for this to work properly. I will give you reason for each.-
You are loading your data with the postServiceCall() method which has an asynchronous network call. There is no way to know when the controller is done fetching the data to the arrImageItems array. So, you should have used a completion handler.
Now you are updating the collectionView within the asynchronous dataTask which a background thread. BIG mistake. Whenever you have any UI related task, you do it under the main thread. So, you could refactor the APIReqeustManager.sharedInstance.uploadMultipartFormData() part of your code following way-
APIReqeustManager.sharedInstance.uploadMultipartFormData(param: parameters, url: CommonUrl.edit_profile_images, image: imageProfile, fileName: "image", vc: self, isHeaderNeeded: true) {(responseData) in
print("edit profile result \(responseData)")
if let result = responseData.dict?["result"] as? NSDictionary{
let success = result["status"] as? [String : Any]
let message = success?["message"] as? String
if message == "Success"{
let image = result["image"] as? [String : Any]
let picId = image?["id"]
self.arrImageItems.append(ImageItemModel(title: self.titleTextfield.text, imgTitle: self.imageProfile, pic_id: picId as! Double))
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
else{
DispatchQueue.main.async {
self.view.makeToast(CommonMessages.somethingWentWrong)
}
}
}
}
Now unless you want your viewcontroller to show the data in your collectionView only when the action, imgtitleSaveBtn(_:) is triggered, you need to get data everytime, when your view controller appeared on screen. To fix that issue, you should get the data in the viewWillAppear(_:) method like-
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
postServiceCall()
}
Now, the above two edits should fix your issue depending on how you want to load your collectionview but your code is breaking quite some coding standards. Coding standards sounds like a clique but trust me you want to follow those if you ever want to update the capability of your app without breaking it. The following is just some hints-
Whenever you are in an asynchronous call, you should consider calling a completion handler for returning your data.
Should look into your methods, you are dangerously breaking the single responsibility principal.
In more than one place, you force unwrapped. Bad idea. You need your system to have a fail safe rather than just crashing on you.
Update 2:
Updates with a design pattern:
Compartmentalise your code in MVC pattern. Put the ImageItemModel class in its own file. See the image below to understand the design-
Customize the collectionViewCell within the ImageCollectionViewCell. Let's assume your custom cell has only the outlets.
class ImageCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imgView: UIImageView!
#IBOutlet weak var lblTitle: UILabel!
#IBOutlet weak var deleteButton: UIButton!{
didSet{
deleteButton.addTarget(self, action: #selector(deleteService(_:)), for: .touchUpInside)
}
}
// however this could easily be done with IBAction
#objc func deleteService(_ sender: UIButton){
}
}
Update the postServiceCall and return the data to your controller with a completion handler, means when the postServiceCall is done executing, an array of images or an empty array should be returned based on success or failure. Then the controller can decide what to do with the data, in your case update UI. with couple of refactoring, here is the updated controller code.
import UIKit
import EasyImagePicker
class EditProfileImageViewController: UIViewController {
#IBOutlet weak var collectionView: UICollectionView!{ //for troubleshooting
didSet{ //purpose, do it from code
collectionView.delegate = self
collectionView.dataSource = self
}
}
#IBOutlet weak var titleTextfield: UITextField!
private var imageProfile : UIImage?
private var imagePicker : EasyImagePicker? // you never used this var.
var arrImageItems = [ImageItemModel]()
// any time a view controller appears on screen this method gets called.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
reloadMyCollectionView()
}
#IBAction func imgtitleSaveBtn(_ sender: Any) {
reloadMyCollectionView()
}
fileprivate func reloadMyCollectionView(){
postServiceCall{ images in
self.arrImageItems = images
DispatchQueue.main.async {
self.collectionView.reloadData()
}
}
}
// look into escaping closures to understand, why you need it here
fileprivate func postServiceCall(completed: #escaping(_ images: [ImageItemModel])->Void){
// don't force unwrap, get optional values safely with guard let
guard let titleText = titleTextfield.text, titleText == "" else{
return
}
let parameters = ["image_title" : titleText]
APIReqeustManager.sharedInstance.uploadMultipartFormData(param: parameters, url: CommonUrl.edit_profile_images, image: imageProfile, fileName: "image", vc: self, isHeaderNeeded: true) {(responseData) in
print("edit profile result \(responseData)")
//capture the data in local scope and return that array with a completion handler
var imageItems = []
if let result = responseData.dict?["result"] as? NSDictionary{
let success = result["status"] as? [String : Any]
let message = success?["message"] as? String
if message == "Success"{
let image = result["image"] as? [String : Any]
let picId = image?["id"]
imageItems.append(ImageItemModel(title: self.titleTextfield.text, imgTitle: self.imageProfile, pic_id: picId as! Double))
}
}
self.completed(imageItems) // if there is nothing in result,
//imageItems will be empty, otherwise it will have imageItemModel data
}
}
}
extension EditProfileImageViewController : UICollectionViewDelegate,UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arrImageItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ImageCollectionViewCell", for: indexPath) as? ImageCollectionViewCell{
cell.imgView.image = arrImageItems[indexPath.item].profileImage
cell.lblTitle.text = arrImageItems[indexPath.row].title
cell.deleteButton.tag = indexPath.row
//cell.deleteButton.addTarget(self, action: #selector(deleteService(sender:)), for: UIControl.Event.touchUpInside)
return cell
}
else{
return UICollectionViewCell()
}
}
}
Notice postServiceCall and cellForItemAt methods.
If you still have the same issue then you need to show your whole code to get any further help.

Related

Search Bar with JSON Objects in TableView - Swift

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate,UISearchDisplayDelegate{
#IBOutlet weak var recipeTable: UITableView!
#IBOutlet weak var searchbarValue: UISearchBar!
// search functionality
var filteredAnswers: [JSON]?
func searchBarSearchButtonClicked(_ searchBar: UISearchBar){
self.filteredAnswers?.removeAll()
if (searchBar.text?.isEmpty)! {
self.filteredAnswers = self.recipes } else {
if self.recipes.count > 0 {
for i in 0...self.recipes.count - 1 {
let answer = self.recipes[i] as [Dictionary<String, AnyObject>]
if answer.title.range(of: searchBar.text!, options: .caseInsensitive) != nil {
self.filteredAnswers.append(answer)
}
}
}
}
recipeTable.reloadData();
recipeTable.reloadInputViews();
searchBar.resignFirstResponder()
}
//end search parameters
// tableview functionionalitys
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipes.count
}
// tableview functionalities
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! RecipeTableViewCell
cell.recipeLabel.text = recipes[indexPath.row].title
//cell.textLabel?.text = recipe.title
//cell.imageView?.image = recipe.imageUrl
return cell
}
// structs for json
struct Root : Decodable {
let count : Int
let recipes : [Recipe]
}
struct Recipe : Decodable { // It's highly recommended to declare Recipe in singular form
let recipeId : String
let imageUrl, sourceUrl, f2fUrl : URL
let title : String
let publisher : String
let socialRank : Double
let page : Int?
let ingredients : [String]?
}
//recipes is array of Recipes
var recipes = [Recipe]() // array of recipes
//unfiltered recipes to put into search
var filteredRecipes = [Recipe]()
fileprivate func getRecipes() {
let jsonURL = "http://food2fork.com/api/search?key=264045e3ff7b84ee346eb20e1642d9d9"
//.data(using: .utf8)!
//let somedata = Data(jsonURL.utf8)
guard let url = URL(string: jsonURL) else{return}
URLSession.shared.dataTask(with: url) {(data, response , err) in
if let response = response as? HTTPURLResponse, response.statusCode != 200 {
print(response.statusCode)
return
}
DispatchQueue.main.async {
if let err = err{
print("failed to get data from URL",err)
return
}
guard let data = data else{return}
//print(String(data: data, encoding: .utf8))
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let result = try decoder.decode(Root.self, from: data)
self.recipes = result.recipes
//print(result.recipes)
self.recipeTable.reloadData()
}catch let jsonERR {
print("Failed to decode",jsonERR)
}
}
}.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
//search functionalities
self.searchbarValue.delegate = self
//call json object
getRecipes()
}
}
I am trying to implement a search bar that takes ingredients from the JSON Object and shows the recipes that contain those ingredients in my table view. I am hoping for some best practices and help with this. I have tried a couple different strategies and none seem to be working.
This is the last one I have tried to implement, but I am getting errors in the search functionality.
self.recipes.count in searchBarSearchButtonClicked Cannot assign value
of type '[ViewController.Recipe]' to type '[JSON]?
But I'm also getting an assertion failure in -
[UISearchResultsTableView
_dequeueReusableCellWithIdentifier:forIndexPath:usingPresentationValues:]
I would like to get help but also improve and find the best way to do this. Thanks.
First of all your logic to filter the recipes cannot work and is very, very inefficient. It seems you copied and pasted the code from a completely unrelated source.
Basically the type of the data source array and the type of the filtered array must be the same, so you have to use filteredRecipes rather than filteredAnswers.
To filter the recipes with matching ingredients use filter and contains
func searchBarSearchButtonClicked(_ searchBar: UISearchBar){
filteredRecipes.removeAll()
if let searchText = searchBar.text, !searchText.isEmpty {
self.filteredRecipes = self.recipes.filter { recipe in
guard let ingredients = recipe.ingredients else { return false }
return ingredients.contains { $0.range(of: searchText, options: .caseInsensitive) != nil }
}
} else {
self.filteredRecipes = self.recipes
}
recipeTable.reloadData();
recipeTable.reloadInputViews();
searchBar.resignFirstResponder()
}
Actually this code is supposed to be executed in the delegate method
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
rather than in searchBarSearchButtonClicked
And – very important – you have to add a boolean property to indicate isSearching and in all related datasource and delegate methods you have to add a condition to show the data of filteredRecipes if isSearching is true.

Swift4 UITableView: JSON data loading correctly but throwing error on assigning value

I have some JSON data that looks like this
{
"fullName": "John Doe",
"imageUrl": "https://www.example.com/images/about/team/john.jpg",
"titles": [
"Founder & President",
"Advisor"
]
},
{
"fullName": "Jane Doe",
"imageUrl": "https://www.example.com/images/about/team/jane.jpg",
"titles": [
"Executive Vice President",
"Director of Advisor Services and Marketing"
]
},
The data gets loaded and parses correctly, but when I run the code I get an error. I think it has to do with the titles section having multiple titles and it doesn't know how to display the titles correctly.
Here is my code.
This is the initial structure.
import UIKit
class Managers: Codable {
let managers: [Manager]
init (managers: [Manager]) {
self.managers = managers
}
}
class Manager: Codable {
let imageUrl: String?
let fullName: String?
let titles: [titles]
init(imageUrl: String?, fullName: String?, titles: [titles]) {
self.imageUrl = imageUrl
self.fullName = fullName
self.titles = titles
}
struct titles: Codable {
let title: String
}
}
This is the Management cell that displays the layout of the image, name and title.
import UIKit
class ManagementCell: UITableViewCell {
#IBOutlet weak var imageUrl: UIImageView!
#IBOutlet weak var fullNameLbl: UILabel!
#IBOutlet weak var titlesLbl: 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
}
}
This is the view controller
import UIKit
class ManagementViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
final let url = URL(string: "Data from above goes here")
private var managers = [Manager]()
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
downloadJson()
tableView.tableFooterView = UIView()
}
func downloadJson() {
guard let downloadURL = url else { return }
URLSession.shared.dataTask(with: downloadURL) { data, urlResponse, error in
guard let data = data, error == nil, urlResponse != nil else {
print("Something went wrong")
return
}
print("downloaded")
do
{
let decoder = JSONDecoder()
let downloadedManagers = try decoder.decode([Manager].self, from: data)
self.managers = downloadedManagers
DispatchQueue.main.async {
self.tableView.reloadData()
}
} catch {
print("Something went wrong after download")
}
}.resume()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return managers.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "ManagementCell") as? ManagementCell else { return UITableViewCell() }
cell.fullNameLbl?.text = managers[indexPath.row].fullName
cell.titlesLbl?.text = managers[indexPath.row].titles
if let imageURL = URL(string: managers[indexPath.row].imageUrl!) {
DispatchQueue.global().async {
let data = try? Data(contentsOf: imageURL)
if let data = data {
let image = UIImage(data: data)
DispatchQueue.main.async {
cell.imageUrl.image = image
cell.imageUrl.layer.cornerRadius = 60
cell.imageUrl.clipsToBounds = true
cell.imageUrl.contentMode = .scaleAspectFit
cell.imageUrl.backgroundColor = UIColor.lightGray
cell.imageUrl.layer.borderWidth = 5
cell.imageUrl.layer.borderColor = UIColor.clear.cgColor
}
}
}
}
return cell
}
This line of code is throwing an error:
cell.titlesLbl?.text = managers[indexPath.row].titles
error is Cannot assign value of type '[Manager.titles]' to type 'String?'
Does anyone have a workaround for this. I believe that I have to create a separate loop for the titles since it also has an array of options. Any suggestions will be very much appreciated.
On a separate note for the image if an image is missing is causes the app to crash. How do I set a generic image if an image in the JSON data isn't present?
Because managers[indexPath.row].titles returns an array of Strings. Peeking into your data, it looks like the first title in that array is the most recent title the manager holds. You can append an index or call .first to get that title:
cell.titlesLbl?.text = managers[indexPath.row].titles.first?.title
// or
cell.titlesLbl?.text = managers[indexPath.row].titles[0].title
// or to show all past titles, comma separated
cell.titlesLbl?.text = managers[indexPath.row].titles
.map({ $0.title })
.joined(separator: ", ")
The difference is that .first won't throw an error if the titles array is empty. You get a blank label instead. [0] will throw a index out of bounds error if your array is empty.

Swift 3, Alamofire 4, JSON Dictionary: Only displaying last JSON entry

For some reason, my code is only displaying the last entry in the JSON file... No errors, just not properly displaying all the sets in the UICollectionView.
class vcWatch: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
#IBOutlet weak var myActivityIndicator: UIActivityIndicatorView!
#IBOutlet weak var myCollectionView: UICollectionView!
var images:[String] = [] // #IBOutlet weak var imageCell: UIImageView!
var lableTitles:[String] = [] // #IBOutlet weak var labelCell: UILabel!
let pageURL = "http://alifetouched.com/lib/videos.json.php"
override func viewDidLoad() {
super.viewDidLoad()
loadImages()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let myCell:cvCell = collectionView.dequeueReusableCell(withReuseIdentifier: "VideoCell", for: indexPath) as! cvCell
myCell.labelCell.text = self.lableTitles[indexPath.row]
let imageString = self.images[indexPath.row]
let imageUrl = NSURL(string: imageString)
let imageData = NSData(contentsOf: imageUrl! as URL)
if(imageData != nil){
myCell.imageCell.image = UIImage(data: imageData! as Data)
}
return myCell
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath){
print("User Tapped: \(indexPath.row)")
}
func loadImages() {
myActivityIndicator.isHidden = false
myActivityIndicator.startAnimating()
Alamofire.request(pageURL)
.validate()
.responseJSON { (response) in
guard response.result.isSuccess else {
print("Error with response: \(response.result.error)")
return
}
guard let dict = response.result.value as? Dictionary <String,AnyObject> else {
print("Error with dictionary: \(response.result.error)")
return
}
guard let dictData = dict["VideoJSON"] as? [Dictionary <String,AnyObject>] else {
print("Error with dictionary data: \(response.result.error)")
return
}
for videos in dictData {
self.myActivityIndicator.isHidden = true
self.myActivityIndicator.stopAnimating()
self.images = [videos["icon_url"] as! String]
self.lableTitles = [videos["title"] as! String]
self.myCollectionView.reloadData()
}
return
}
}
}
I know I am just not thinking straight...Thank you in advance for your time.
The issue is inside your for loop, inside that you need to append the object in array instead of that you are initializing the Array with single object, also you need to reload the collectionView outside the for loop after all the object added in array not inside the loop. Also you need to put myActivityIndicator before the for loop or after the loop not inside the loop because it will execute same code multiple times and there no need of that.
self.myActivityIndicator.isHidden = true
self.myActivityIndicator.stopAnimating()
for videos in dictData {
self.images.append(videos["icon_url"] as! String)
self.lableTitles.append([videos["title"] as! String)
}
self.myCollectionView.reloadData()
Note: One suggestion instead of maintaining two different arrays of type [String] you need to main Single array of type [[String: Any]] and use that array in your collectionView method like myCell.labelCell.text = self.dicArr[indexPath.row]["title"] as? String.
first create array to get the alamofire response. than add the response name "VideoJSON" array into your array
than give count of your array in numberofiteminsection
and than after get the url from that array which you added earlier
your this method only get the last entry
for videos in dictData {
self.myActivityIndicator.isHidden = true
self.myActivityIndicator.stopAnimating()
self.images = [videos["icon_url"] as! String]
self.lableTitles = [videos["title"] as! String]
self.myCollectionView.reloadData()
}

GET works only once

I'm new to iOS programming, so my question might not be complicated but I'm still struggling to find the best solution. Any help will be highly appreciated!
I'm trying to send GET request every time the user opens the app. I wrote the function loadMenu() that collects the data from a json file on the server and populates the table in the app.
The problem is that if I update the json file, it's not reflected in the app. If feels like the loadMenu() part of the code is just ignored.
Here's my code:
import UIKit
class TableViewControllerNew: UITableViewController {
var names = [String]()
var mealDescription = [String]()
var price = [Double]()
override func viewDidLoad() {
super.viewDidLoad()
loadMenu()
}
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 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
var new = NSUserDefaults.standardUserDefaults().objectForKey("names") as! [String]
print("test: \(new.count)")
return new.count
}
func loadMenu() {
print("viewDidLoad works")
// Send HTTP GET
let myUrl = NSURL(string: "http://localhost/myPi/selection/wheyStationSelection.json");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "GET";
NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
dispatch_async(dispatch_get_main_queue()) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
if let meals = json["meals"] as? [[String: AnyObject]] {
for meal in meals {
if let name = meal["name"] as? String {
self.names.append(name)
//NSUserDefaults.standardUserDefaults().setObject(self.names, forKey: "test1") as! [String]
//var new = NSUserDefaults.standardUserDefaults().objectForKey("test1") as? [String]
//print(new)
}
if let mealDescription = meal["mealDescription"] as? String {
self.mealDescription.append(mealDescription)
}
if let price = meal["price"] as? Double {
self.price.append(price)
}
}
}
} catch {
print("error serializing JSON: \(error)")
}
NSUserDefaults.standardUserDefaults().setObject(self.names, forKey: "test1") as! [String]
//print(self.names)
//print(self.mealDescription)
//print(self.price)
}
}).resume()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdenifier = "MealTableViewCell"
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdenifier, forIndexPath: indexPath) as! MealTableViewCell
var new = NSUserDefaults.standardUserDefaults().objectForKey("names") as! [String]
let name = new[indexPath.row]
//print(name)
cell.mealNameLabel.text = name
return cell
}
#david is right, if you place your loadMenu() method in viewDidAppear() it will be called each and every time your view appears. You can read more about the various lifecycle phases of a UIViewController here
One other thing. It is not clear to me whether your loadMenu() isn't called every time or whether you are just not seeing the updated content.
I can see that you are not reloading your table view when the JSON has been updated. Therefore your TableView don't know that any updates has occurred and will not render again and you won't see any updates.
Therefore, right after this line:
NSUserDefaults.standardUserDefaults().setObject(self.names, forKey: "test1")
You should tell your tableView to reload itself like so:
tableView.reloadData()
So you have:
NSUserDefaults.standardUserDefaults().setObject(self.names, forKey: "test1")
tableView.reloadData()
That should cause all your "render the TableView" methods to be called again, but this time with the new data and you should see the updated content.
Hope this helps you.
If you call loadMenu() in viewDidAppear(animated:) instead of viewDidLoad(), then it will be called every time you leave your app and reopen it.

JSON data not displaying in NSTableView

I am fairly new to Swift but I have a NSTableView that is not displaying any of my data. My JSON data is being printed in the console perfectly and I thought that my cellView would display in my textField all my values but I get nothing back. I have my Table set up to where my 'Table Cell View' has an identifier of 'cell' so I believe they are linked correctly. I am not receiving any errors in the console but my data is still not displaying. Any help would be greatly appreciated.
import Cocoa
class ViewController: NSViewController, NSTableViewDataSource, NSTableViewDelegate {
#IBOutlet var tableView: NSTableView!
var values: NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
get();
}
override var representedObject: Any? {
didSet {
}
}
func get(){
let url = NSURL(string: "http://myurl")
let data = NSData(contentsOf: url as! URL);
values = try! JSONSerialization.jsonObject(with: data! as Data,options: JSONSerialization.ReadingOptions.mutableContainers) as! NSArray
tableView.reloadData();
print(values);
}
func numberOfRows(in tableView: NSTableView) -> Int {
return self.values.count;
}
private func tableView(tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let cellView = tableView.make(withIdentifier: "cell", owner: self) as! NSTableCellView
cellView.textField!.stringValue = self.values.object(at: row) as! String
return cellView
}
did you make sure your table view knows it's delegate and data source?, if not, add this to viewDidLoad
self.tableView.delegate = self
self.tableView.dataSource = self