class DropTvViewController: UIViewController , UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var dataTransfer = DataTransfer()
var responseString : String = ""
let storeData = StoreData()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
let pfod = PostForData()
pfod.forData
{ jsonString in
self.responseString = jsonString as String
var dict = self.dataTransfer.jsonToArray(self.responseString)!
if let x: AnyObject = dict.valueForKey("readlist")
{
println( dict.count )
println("X + \(x)")
for var i = 0 ; i < dict.count-1 ; i+=2
{
println("i : \(i)")
let y: AnyObject = x.objectAtIndex(i)
let z: AnyObject? = y.objectForKey("epipic")
let title : AnyObject? = y.objectForKey("epititle")
let time : AnyObject? = y.objectForKey("droptagcreatetime")
let pg : AnyObject? = y.objectForKey("pgname")
var imagessss = UIImage (data : pfod.forPicture())
self.storeData.add(title as! String, aFs: pg as! String, aTs: time as! String, ph: imagessss! , field1s: z as! String, field2s: z as! String, field3s: z as! String, field4s: z as! String )
// I do reload in here,but it will delay about ten seconds.
// I am sure the data is ready to read
self.tableView.reloadData()
}
}
}
}
You can use self.tableView.reloadData() which you are doing, but just in the wrong part of the loop. Just move it outside and you should be fine :)
If you're looking to reload a specific table cell then try: self.tableView.reloadRowsAtIndexPaths(paths, withRowAnimation: UITableViewRowAnimation.None)
Answer taken from here: https://stackoverflow.com/a/26709571/4891259
Related
I have 2 files. First - TransactionsViewController. Second - GetTransactions. When I open TransactionsViewController the table from that view loads faster than the date from GetTransactions. Therefore, it is displayed blank. How to fix it?
Here is the code of TransactionsViewController viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
GetTransactions().getTransactions()
clientsCount = GetTransactions.transactions.count
setupNavBar()
createTable()
refreshSetup()
}
Here is the code of GetTransactions:
class GetTransactions {
static var transactionsArr = [[String : Any]]()
static var transactions = [TransactionInfo]()
let URL_GET_TRANSACTIONS = "https://mashkov.dev/sites/default/BankApp/Transactions/Transactions.php"
func getTransactions(){
GetTransactions.transactionsArr.removeAll()
AF.request(URL_GET_TRANSACTIONS).responseJSON{ (response) in
if (response.value as? [[String : Any]]) != nil {
GetTransactions.transactionsArr = response.value as! [[String : Any]]
}
self.convertData()
print(GetTransactions.transactions)
}
}
func convertData() {
GetTransactions.transactions.removeAll()
for transaction in GetTransactions.transactionsArr {
let cl = TransactionInfo(id: transaction["id"] as! String,
payee: transaction["payee_account_id"] as! String,
sender: transaction["sender_account_id"] as! String,
transDate: transaction["trans_date"] as! String,
amount: transaction["amount"] as! String,
isSuccessfully: Bool((transaction["isSuccessfully"] as! String)) ?? true)
GetTransactions.transactions.append(cl)
}
}
}
What you need is a closure / block to be passed as an argument
class GetTransactions {
static var transactionsArr = [[String : Any]]()
static var transactions = [TransactionInfo]()
let URL_GET_TRANSACTIONS = "https://mashkov.dev/sites/default/BankApp/Transactions/Transactions.php"
func getTransactions(completion block: () -> ()){
GetTransactions.transactionsArr.removeAll()
AF.request(URL_GET_TRANSACTIONS).responseJSON{ (response) in
if (response.value as? [[String : Any]]) != nil {
GetTransactions.transactionsArr = response.value as! [[String : Any]]
}
self.convertData()
print(GetTransactions.transactions)
block()
}
}
func convertData() {
GetTransactions.transactions.removeAll()
for transaction in GetTransactions.transactionsArr {
let cl = TransactionInfo(id: transaction["id"] as! String,
payee: transaction["payee_account_id"] as! String,
sender: transaction["sender_account_id"] as! String,
transDate: transaction["trans_date"] as! String,
amount: transaction["amount"] as! String,
isSuccessfully: Bool((transaction["isSuccessfully"] as! String)) ?? true)
GetTransactions.transactions.append(cl)
}
}
}
And you call it using,
GetTransactions().getTransactions {
clientsCount = GetTransactions.transactions.count
//reload your tableView here
}
I am currently building a table view and I noticed that after my table view is populated I am getting two search bar fields. My original intention was to have only one search bar field appear (shown on my interface) I can't seem to figure out what this happens. When I try to delete the search bar from my interface then my table view will not load and populate data.
Here is a screenshot of the interface storyboard:
Here is the screenshot of when I run the app:
Here is some code including my viewDidLoad:
EDIT: Added TableView Code
class AddHarvestPlanViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var AddHarvestPlanPluCodeTable: UITableView!
let searchController = UISearchController(searchResultsController: nil)
override func viewDidLoad() {
super.viewDidLoad()
findPluCodeParents(searchTextField: "apple")
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Find your Commodity"
navigationItem.searchController = searchController
definesPresentationContext = true
AddHarvestPlanPluCodeTable.delegate = self
AddHarvestPlanPluCodeTable.dataSource = self
AddHarvestPlanPluCodeTable.reloadData()
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count = harvestCommodities.count
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AddPluCodeCustomCell", for: indexPath) as! AddPluCodeCustomCell
do{
let item = harvestCommodities[indexPath.row]
cell.commodity?.text = item.plu_code_commodity
cell.package?.text = "Cases"
return cell
}
}
func findPluCodeParents(searchTextField:String){
let searchText = searchTextField
print("Searching for....",searchTextField)
let aggriEndpoint: String = "https://xxxx.xxxx.com/xxxx/xxxxx"
let url = URL(string:aggriEndpoint)
var urlRequest = URLRequest(url:url!)
urlRequest.httpMethod = "GET"
let session = URLSession.shared
print("running task")
let task = session.dataTask(with: urlRequest, completionHandler: {data,response,error -> Void in
do{
print("All finiished")
print(data)
if let json = try JSONSerialization.jsonObject(with: data!) as? [[String:Any?]]{
// print(json)
for item in json{
print(item as? [String:Any?])
var active = item["active"] as? Bool
let cases_per_week = (item["cases_per_week"] as! NSString).doubleValue
var cases_per_palette = item["cases_per_pallette"] as? Int
var lbs_per_week = (item["lbs_per_week"] as! NSString).doubleValue
var cases_per_week_avg = item["cases_per_week_avg"] as? Int
var pounds_per_case = item["pounds_per_case"] as? Int
var repeat_harvest = item["repeat_harvest"] as? Bool
var harvest_week_count = item["harvest_week_count"] as? Int
var plant_days = item["plant_days"] as? Int
var pounds_per_acre = item["pounds_per_acre"] as? Int
var options = item["options"] as? Int
var plu_code_variety = item["plu_code_variety"] as? String
var plu_code_commodity = item["plu_code_commodity"] as? String
var id = item["id"] as? Int
var plu_code = item["plu_code"] as? Int
var acres = item["acres"] as? Int
self.harvestCommodities.append(PluCode(id: id!, commodity: plu_code_commodity!, cases_per_week_avg: cases_per_week_avg!, repeat_harvest: repeat_harvest!, cases_per_week: cases_per_week, lbs_per_week: lbs_per_week, acres: acres!, plu_code: plu_code!, active: active!, options: options!, plant_days: plant_days!, plu_code_commodity: plu_code_commodity!, plu_code_variety: plu_code_variety!, cases_per_palette: cases_per_palette!, harvest_week_count: harvest_week_count!, pounds_per_acre: pounds_per_acre!))
}
}
DispatchQueue.main.async {
self.AddHarvestPlanPluCodeTable.reloadData()
}
} catch let error{
print("error")
}
})
task.resume()
}
Either remove the code where you create the upper Search Bar, ("let searchController = UISearchController(searchResultsController: nil)") and then connect an IBOutlet to the one you have created on the interface to your swift file, or remove the one on the storyboard and use the one you have created in your code, and connect the results to your table view
I want to add strings from an array of dictionary from backend.
but it's always empty outside the fetch function
//fetch data
func fetchFaqs(){
let manager = APIManager()
manager.parsingGet(url: BaseURL.faqs) { (JSON, Status) in
if Status {
let dict = JSON.dictionaryObject
let data = dict!["data"] as! [[String:Any]]
self.faqs = data as! [[String : String]]
}
}
}
//Viewdidload
class FaqViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
var faqs = [[String:String]]()
var questions = NSMutableArray()
var answers = NSMutableArray()
#IBOutlet var faqsTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
fetchFaqs()
self.faqsTableView.reloadData()
print(faqs)
// faqsTableView.rowHeight = UITableView.automaticDimension
// faqsTableView.estimatedRowHeight = 600
}
}
Reload the tableview inside the api call closure in Main thread
func fetchFaqs(){
let manager = APIManager()
manager.parsingGet(url: BaseURL.faqs) { (JSON, Status) in
if Status {
let dict = JSON.dictionaryObject
let data = dict!["data"] as! [[String:Any]]
self.faqs = data as! [[String : String]]
DispatchQueue.main.async {
self.faqsTableView.reloadData()
}
}
}
}
I've been trying to display a plist file in NSTableView for days. I've read a lot, but so far only found instructions for iOS. My problem is that the individual values are not displayed individually in the NStableView. Only the whole plist file in a cell is always displayed.
I hope someone can help me, because I just can not get any further. I'm still a freshman in Swift.
I uploaded my Plist, if someone can explain me where the error lies.
https://www.dropbox.com/s/1t8c4uldwdtp3wk/Archiv.zip?dl=0
import Cocoa
class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
#IBOutlet weak var tableView: NSTableView!
#IBOutlet weak var ntext: NSTextField!
#IBOutlet weak var schwarztext: NSTextField!
#IBOutlet weak var cyantext: NSTextField!
#IBOutlet weak var magentatext: NSTextField!
#IBOutlet weak var gelbtext: NSTextField!
#IBOutlet weak var lightcyantext: NSTextField!
#IBOutlet weak var lightmtext: NSTextField!
var n : String? = nil; // n
var schwarz : String? = nil; // Schwarz
var cyan : String? = nil; // Cyan
var magenta : String? = nil; // Magenta
var gelb : String? = nil; // Gelb
var lightc : String? = nil; // Light Cyan
var lightm : String? = nil; // Light Magenta
let AUTO_PLIST_JOBS_PATH = Bundle.main.path(forResource: "Jobs", ofType: "plist")
let AUTO_PLIST_JOBS_KEY_N = "n" // n
let AUTO_PLIST_JOBS_KEY_SCHWARZ = "schwarz" // Schwarz
let AUTO_PLIST_JOBS_KEY_CYAN = "cyan" // Cyan
let AUTO_PLIST_JOBS_KEY_MAGENTA = "magenta" // Magenta
let AUTO_PLIST_JOBS_KEY_GELB = "gelb" // Gelb
let AUTO_PLIST_JOBS_KEY_LIGHTC = "lightc" // Light Cyan
let AUTO_PLIST_JOBS_KEY_LIGHTM = "lightm" // Light Magenta
var _jobss = [Jobs]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view.
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
//let path = Bundle.main.path(forResource: "Jobs", ofType: "plist")
//let myJobs100 = NSArray(contentsOfFile: path!)
//return myJobs100
let path = Bundle.main.path(forResource: "Jobs", ofType: "plist")
let url = URL(fileURLWithPath: path!)
let data = try! Data(contentsOf: url)
let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil)
let dictArray = plist as! [[String:String]]
return dictArray
}
func allJobss() -> [Jobs]{
if _jobss.count > 0 {
return _jobss
}
if let allDatas = NSArray(contentsOfFile: AUTO_PLIST_JOBS_PATH!) {
for dict in allDatas {
guard let dict = dict as? [String: AnyObject] else {continue}
let jobs = Jobs()
jobs.n = dict[AUTO_PLIST_JOBS_KEY_N] as? String // n
jobs.schwarz = dict[AUTO_PLIST_JOBS_KEY_SCHWARZ] as? String // Schwarz
jobs.cyan = dict[AUTO_PLIST_JOBS_KEY_CYAN] as? String // Cyan
jobs.magenta = dict[AUTO_PLIST_JOBS_KEY_MAGENTA] as? String // Magenta
jobs.gelb = dict[AUTO_PLIST_JOBS_KEY_GELB] as? String // Gelb
jobs.lightc = dict[AUTO_PLIST_JOBS_KEY_LIGHTC] as? String // Light Cyan
jobs.lightm = dict[AUTO_PLIST_JOBS_KEY_LIGHTM] as? String // Light Magenta
_jobss.append(jobs)
}
}
return _jobss
}
func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
return 80
}
func numberOfRows(in tableView: NSTableView) -> Int {
return allJobss().count
}
func tableViewSelectionDidChange(_ notification: Notification) {
print(tableView.selectedRow)
let path = Bundle.main.path(forResource: "Jobs", ofType: "plist")
let url = URL(fileURLWithPath: path!)
let data = try! Data(contentsOf: url)
let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil)
let dictArray = plist as! [[String:String]]
// [[String:String]] is equivalent to Array< Dictionary<String, String> >
print(dictArray[tableView.selectedRow]["n"] as Any)
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
NSTableview
Plist
I hope someone can help me.
First of all this is Swift. Variable names including underscore characters are ugly and objective-c-ish.
Your workflow is wrong. objectValueFor is called very often (once for each row) and is supposed to return just the object for the given row/column. Reading the same data again and again is horrible.
Load the data once in viewDidLoad and decode the Plist directly into a class. A class is required to be able to bind the values
#objcMembers
class Job : NSObject, Decodable {
dynamic var n, schwarz, cyan, magenta, gelb, lightc, lightm : String
}
#objc dynamic var jobs = [Job]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
// Do any additional setup after loading the view.
let url = Bundle.main.url(forResource: "Jobs", withExtension: "plist")!
let data = try! Data(contentsOf: url)
jobs = try! PropertyListDecoder().decode([Job].self, from: data)
tableView.reloadData()
}
In objectValueFor just return the item for the row
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return jobs[row]
}
the other delegate methods are
func numberOfRows(in tableView: NSTableView) -> Int {
return jobs.count
}
func tableViewSelectionDidChange(_ notification: Notification) {
let selectedRow = tableView.selectedRow
if selectedRow == -1 {
print("Nothing selected")
} else {
print("Row \(selectedRow) selected")
}
}
You have to bind the values to text fields. Open Interface Builder, ⌃⇧-click on the left-most text field (Table View Cell) in the table view, select Table View Cell, press ⌥⌘7 to open the Bindings Inspector, click on the disclosure triangle below Value, Check the checkbox Bind to Table Cell View, in the Model Key Path text field write objectValue.n. Bind the other text fields in the row to the corresponding properties (objectValue.schwarz etc.).
You can delete
var n : String? = nil; // n
var schwarz : String? = nil; // Schwarz
var cyan : String? = nil; // Cyan
var magenta : String? = nil; // Magenta
var gelb : String? = nil; // Gelb
var lightc : String? = nil; // Light Cyan
var lightm : String? = nil; // Light Magenta
let AUTO_PLIST_JOBS_PATH = Bundle.main.path(forResource: "Jobs", ofType: "plist")
let AUTO_PLIST_JOBS_KEY_N = "n" // n
let AUTO_PLIST_JOBS_KEY_SCHWARZ = "schwarz" // Schwarz
let AUTO_PLIST_JOBS_KEY_CYAN = "cyan" // Cyan
let AUTO_PLIST_JOBS_KEY_MAGENTA = "magenta" // Magenta
let AUTO_PLIST_JOBS_KEY_GELB = "gelb" // Gelb
let AUTO_PLIST_JOBS_KEY_LIGHTC = "lightc" // Light Cyan
let AUTO_PLIST_JOBS_KEY_LIGHTM = "lightm" // Light Magenta
func allJobss() -> [Jobs]{
if _jobss.count > 0 {
return _jobss
}
if let allDatas = NSArray(contentsOfFile: AUTO_PLIST_JOBS_PATH!) {
for dict in allDatas {
guard let dict = dict as? [String: AnyObject] else {continue}
let jobs = Jobs()
jobs.n = dict[AUTO_PLIST_JOBS_KEY_N] as? String // n
jobs.schwarz = dict[AUTO_PLIST_JOBS_KEY_SCHWARZ] as? String // Schwarz
jobs.cyan = dict[AUTO_PLIST_JOBS_KEY_CYAN] as? String // Cyan
jobs.magenta = dict[AUTO_PLIST_JOBS_KEY_MAGENTA] as? String // Magenta
jobs.gelb = dict[AUTO_PLIST_JOBS_KEY_GELB] as? String // Gelb
jobs.lightc = dict[AUTO_PLIST_JOBS_KEY_LIGHTC] as? String // Light Cyan
jobs.lightm = dict[AUTO_PLIST_JOBS_KEY_LIGHTM] as? String // Light Magenta
_jobss.append(jobs)
}
}
return _jobss
}
What I am trying to do is to have data from Parse be retrieved from columns by object order. All labels are connected to their respective outlets and all of the outputs retrieve their correct data.
When I run it and open a cell in the tableview it crashes and gives me Thread 1: EXC_BAD_INSTRUCTION (code=EXC>I386_INVOP, subcode=0x0) on this line: self.navBar.topItem?.title = output1 if I select the first cell, and then on this line: self.navBar.topItem?.title = output1b if I select the second cell.
Here is the full function:
firstObject is grabbing the first object in the "eventsdetail" column
secondObject is grabbing the second object in the "eventsdetail" column
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
var query = PFQuery(className: "eventsdetail")
let runkey = query.orderByAscending("ID")
runkey.findObjectsInBackgroundWithBlock {
(objects: [PFObject]?, error : NSError?) -> Void in
if error == nil {
if let objects = objects as [PFObject]! {
for object in objects {
var firstObject = objects[0]
var secondObject = objects[1]
let output1 = firstObject.objectForKey("navTitle") as! String!
let output2 = firstObject.objectForKey("articleTitle") as! String!
let output3 = firstObject.objectForKey("written") as! String!
let output4 = firstObject.objectForKey("date") as! String!
let output5 = firstObject.objectForKey("article") as! String!
let output1b = secondObject.objectForKey("navTitle") as! String!
let output2b = secondObject.objectForKey("articleTitle") as! String!
let output3b = secondObject.objectForKey("written") as! String!
let output4b = secondObject.objectForKey("date") as! String!
let output5b = secondObject.objectForKey("article") as! String!
if indexPath.row == 0 {
self.performSegueWithIdentifier("0a", sender: nil)
self.tableview.deselectRowAtIndexPath(indexPath, animated: true)
self.navBar.topItem?.title = output1
self.articleTitle.text = output2
self.writtenBy.text = output3
self.date.text = output4
self.article.text = output5
} else if indexPath.row == 1 {
self.performSegueWithIdentifier("0a", sender: nil)
self.tableview.deselectRowAtIndexPath(indexPath, animated: true)
self.navBar.topItem?.title = output1b
self.articleTitle.text = output2b
self.writtenBy.text = output3b
self.date.text = output4b
self.article.text = output5b
}
}
}
}
}
}
If there is an easier way of doing this, please mention it, if not try to just solve this method's problem. I know it isn't the cleanest way of doing things.
I am not sure of how you Parse your data but if it can help you, here's how I would do:
//
// Test.swift
// Test
//
// Created by Charles-Olivier Demers on 16-01-04.
//
import UIKit
//import Parse
class EventViewController: UIViewController, UITableViewDelegate {
private var _info = [EventDetails]()
override func viewDidLoad() {
fetchData()
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("0a", sender: nil)
self.tableview.deselectRowAtIndexPath(indexPath, animated: true)
self.navBar.topItem?.title.text = _info[indexPath.row].navTitle()
self.articleTitle.text = _info[indexPath.row].articleTitle()
self.writtenBy.text = _info[indexPath.row].writtenBy()
self.date.text = _info[indexPath.row].date()
self.article.text = _info[indexPath.row].article()
}
func fetchData() {
let query = PFQuery(className: "eventsDetails")
query.orderByAscending("ID")
query.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
if let objects = objects {
for object in objects {
let navTitleObject = object["navTitle"] as! String
let articleTitleObject = object["articleTitle"] as! String
let writtenByObject = object["writtenByObject"] as! String
let dateObject = object["dateObject"] as! String
let articleObject = object["articleObject"] as! String
_info.append(EventDetails(navTitle: navTitleObject, articleTitle: articleTitleObject, writtenBy: writtenByObject, date: dateObject, article: articleObject))
}
}
}
else {
print("Error #\(error!.code)")
}
}
}
}
class EventDetails {
private var _navTitle: String!
private var _articleTitle: String!
private var _writtenBy: String!
private var _date: String!
private var _article: String!
init(navTitle: String, articleTitle: String, writtenBy: String, date: String, article: String) {
self._navTitle = navTitle
self._article = articleTitle
self._writtenBy = writtenBy
self._date = date
self._article = article
}
func navTitle() -> String {
return _navTitle
}
func articleTitle() -> String {
return _articleTitle
}
func writtenBy() -> String {
return _writtenBy
}
func date() -> String {
return _date
}
func article() -> String {
return _article
}
}
First of all, I would create a class named EventDetails. This class will take all the property of EventsDetails class on Parse. So when you fetch your data, you append the data you fetch in an array of EventDetails class in Swift.
After that in your
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
you take the value in your EventDetails array with the indexPath.row and you fill your Table View.
That is how I would do.