Use global variables outside viewDidLoad() function - ios

I have a global variables within view class, I am doing some functions inside viewDidLoad(), and through those functions I assign some values to those global variables (arrays). But when I try to reuse them outside viewDidLoad() I get their count = 0 like this function:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return prodItem.count;
}
Here's my full code:
import UIKit
class NewViewController: UIViewController, UITableViewDelegate {
//define product details vars
var prodLink = [String]();
var prodImg = [String]();
var prodItem = [String]();
var prodDesc = [String]();
var prodPrice = [String]();
var prodSale = [String]();
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//define url
let url = NSURL(string: "https://www.iravin.com/new")!;
//define task
let task = NSURLSession.sharedSession().dataTaskWithURL(url) {(data, response, error) -> Void in
if let urlContent = data {
let webContent = NSString(data: urlContent, encoding: NSUTF8StringEncoding);
let webArray = webContent?.componentsSeparatedByString("<ul class=\"hProductItems clearfix\">");
let webArray2 = webArray?[1].componentsSeparatedByString("</ul>");
var prodArray = webArray2?[0].componentsSeparatedByString("<li class=\"span3 clearfix\">");
prodArray?.removeAtIndex(0);
for oneProd in (prodArray)! {
var prodData = [String]();
prodData = oneProd.componentsSeparatedByString("\n\t\t\t\t\t\t\t<div class=\"thumbnail\">\n\t\t\t\t\t\t\t\t<a href=\"");
prodData.removeAtIndex(0);
prodData = prodData[0].componentsSeparatedByString("\"><img class=\"lazy\" data-src=\"");
self.prodLink.append(prodData[0]);
prodData = prodData[1].componentsSeparatedByString("\" src=\"img/loading.gif\" alt=\"\"></a>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"thumbSetting\">\n\t\t\t\t\t\t\t\t<div class=\"thumbTitle\">\n\t\t\t\t\t\t\t\t\t<h3>\n\t\t\t\t\t\t\t\t\t<span class=\"invarseColor\">");
self.prodImg.append(prodData[0]);
prodData = prodData[1].componentsSeparatedByString("</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</h3>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div class=\"product-desc\">\n\t\t\t\t\t\t\t\t\t<p>");
if prodData[0].containsString("Sale") {
let prodDataSale = prodData[0].componentsSeparatedByString("</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"label label-info\">Sale");
self.prodItem.append(prodDataSale[0]);
prodData = prodData[1].componentsSeparatedByString("</p>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div class=\"thumbPrice\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span>");
self.prodDesc.append(prodData[0]);
prodData = prodData[1].componentsSeparatedByString("</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<div class=\"thumbButtons\">\n\t\t\t\t\t\t\t\t\t<button rel=\"");
var prodDataPrice = prodData[0].componentsSeparatedByString("<span class=\"strike-through\">");
prodDataPrice = prodDataPrice[1].componentsSeparatedByString("</span>");
self.prodPrice.append(prodDataPrice[0]);
self.prodSale.append(prodDataPrice[1]);
} else {
self.prodItem.append(prodData[0]);
prodData = prodData[1].componentsSeparatedByString("</p>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div class=\"thumbPrice\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<span>");
self.prodDesc.append(prodData[0]);
prodData = prodData[1].componentsSeparatedByString("</span>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<div class=\"thumbButtons\">\n\t\t\t\t\t\t\t\t\t<button rel=\"");
self.prodPrice.append(prodData[0]);
self.prodSale.append(prodData[0]);
}
}
}
}
task.resume();
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return prodItem.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// get an instance of your cell
let cell = tableView.dequeueReusableCellWithIdentifier("prodCell", forIndexPath: indexPath) as! MyCustomTableViewCell;
cell.lblProdItem.text = self.prodItem[indexPath.row];
return cell;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

From ios dev library: Like most networking APIs, the NSURLSession API is highly asynchronous.
You need to reload your tableview after the task has been completed. Right now its starting the task and then looking at the count before it has finished which is why it is 0.
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
task.resume();
}

Related

Tableview doesn't display data in swift 2

I'm working on the tableView in swift 2.2 in xcode 7.3.1 and I'm sure from my code because it's not the first time for me to deal with tableView , I'm pulling data correctly from server and stored it in array but I notice the two function that is related to table view is not called so the table view appear empty for me ! I added cell and linked tableview with view also from layout.
I don't know where is the problem!
class studentTeacherList: UIViewController , UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var studentParentTable: UITableView!
#IBOutlet weak var loadIndicator: UIActivityIndicatorView!
var username:String!
var fromSender: String?
var toRec: String?
var student_id = [Int]()
var parent_id = [String]()
var student_names = [String]()
var parent_name = [String]()
//Sent Data
var s_id:Int = 0
var s_name = ""
var p_id = ""
var p_name = ""
override func viewDidLoad() {
super.viewDidLoad()
studentParentTable.delegate = self
studentParentTable.dataSource = self
let prefs:NSUserDefaults = NSUserDefaults.standardUserDefaults()
username = prefs.objectForKey("user")as! String
fromSender = prefs.objectForKey("Sender")as! String
toRec = prefs.objectForKey("Receiver")as! String
self.loadIndicator.startAnimating()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
self.loadList()
//self.studentParentTable.reloadData()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.loadIndicator.stopAnimating()
})
});
studentParentTable.reloadData()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return student_names.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//This method to define each cell at Table View
let cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
cell.textLabel?.text = student_names[indexPath.row]
cell.detailTextLabel?.text = parent_name[indexPath.row]
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func backButton(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil )
}
func loadList()
{
var normallink = "mylinkhere"
normallink = normallink + "?teacherid=" + self.username
var studentParentURL:NSURL = NSURL (string: normallink)!
let data = NSData(contentsOfURL: studentParentURL)!
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
if let alldata = json["data"] as? [[String: AnyObject]] {
for onedata in alldata {
if let stu_id = onedata["id"] as? Int {
student_id.append(stu_id)
}
if let stu_name = onedata["studentName"] as? String {
student_names.append(stu_name)
}
if let par_id = onedata["parentId"] as? String {
parent_id.append(par_id)
}
if let par_name = onedata["parentName"] as? String {
parent_name.append(par_name)
}
}
}
} catch {
print("Error Serializing JSON: \(error)")
}
print(student_names.count)
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
s_id = student_id[indexPath.row]
s_name = student_names[indexPath.row]
p_id = parent_id[indexPath.row]
p_name = parent_name[indexPath.row]
}
}
It looks like you aren't reloading after this call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
self.loadList()
//self.studentParentTable.reloadData()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.loadIndicator.stopAnimating()
})
});
So you should add studentParentTable.reloadData() after self.loadIndicator.stopAnimating().

swift parsing CSV file from API does not separate with the delimiter

I'm trying to pass the data into the cells of a tableView. The networking communication works because The list of items appear in the first cell.
For example the list come like: sensor1, sensor2, sensor3,....
but it should be like :
sensor1
sensor2
...
this is how I'm parsing the CSV file
struct ParseCVS {
func parseURL (contentsOfURL: NSURL, encoding: NSStringEncoding) -> ([String])?{
let rowDelimiter = ","
var nameOfSensors:[String]?
do {
let content = try String(contentsOfURL: contentsOfURL, encoding: encoding)
print(content)
nameOfSensors = []
let columns:[String] = content.componentsSeparatedByCharactersInSet(NSCharacterSet.newlineCharacterSet()) as [String]
for column in columns {
let values = column.componentsSeparatedByString(rowDelimiter)
if let nameOfSensor = values.first {
nameOfSensors?.append(nameOfSensor)
}
}
}
catch {
print(error)
}
return nameOfSensors
}
}
and this is my TableViewController
class TableViewController: UITableViewController {
// Array which will store my Data
var nameOfSensorsList = [String]()
override func viewDidLoad() {
super.viewDidLoad()
guard let wetterURL = NSURL(string: "http://wetter.htw-berlin.de/phpFunctions/holeAktuelleMesswerte.php?mode=csv&data=1")
else {
return
}
let parseCSV = ParseCVS()
nameOfSensorsList = parseCSV.parseURL(wetterURL, encoding: NSUTF8StringEncoding)!
tableView.estimatedRowHeight = 100.0
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
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 {
return nameOfSensorsList.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! MenuTableViewCell
cell.nameLabel?.text = nameOfSensorsList[indexPath.row]
return cell
}
}
if someone have any ideas I would really appreciate it.
You've forgotten to iterate through an array of "values".
Try something like this:
for column in columns {
let values = column.componentsSeparatedByString(rowDelimiter)
print(values.count)
for value in values {
nameOfSensors?.append(value)
}
}

How to return value from Swift closure?

I'm new at swift closures.
I have this code and i can't extract the values from the forloop into the arrays outside the closure.
Sorry about this question but i have already searched stackflow but without success in this specific case.
Thanks in advance.
var namesArray: [String] = []
var imagesArray: [String] = []
var timesArray: [String] = []
var placesArray: [String] = []
func getData(){
//DATA SOURCE
// Create request for user's Facebook data
let request = FBSDKGraphRequest(graphPath: cmp.pageId, parameters: ["fields": "events"])
// Send request to Facebook
request.startWithCompletionHandler {
(connection, result, error) in
if error != nil {
// Some error checking here
print(error.debugDescription)
} else
if let pageData = result["events"] {
print(result["events"]!!["data"]!![0]["name"])
if let eventDetails = pageData!["data"] {
// EVENT DETAILS FETCH
for var i = 0; i < eventDetails!.count; i++
{
let fetchedEventName = eventDetails![i]["name"] as? String!
let fetchedEventTime = eventDetails![i]["start_time"] as? String!
if eventDetails?[i]["place"]??["name"] != nil {
if let fetchedEventPlace = eventDetails?[i]["place"]??["name"] {
self.placesArray.append(fetchedEventPlace! as! String)
}
} else {
self.placesArray.append("Lisbon")
}
self.namesArray.append(fetchedEventName!)
self.timesArray.append(fetchedEventTime!)
}
print("Name of event: \(self.namesArray)")
}
} else {
print("Error.")
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
getData()
}
EDIT: I want to show the fetched result into a tableview that's already set.
Heres the tableview code.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("previewCell") as? PreviewCell {
var img: UIImage!
let url = NSURL(string: imagesArray[indexPath.row])!
if let data = NSData(contentsOfURL: url){
img = UIImage(data: data)
} else {
img = UIImage(named: "ant")
}
cell.configureCell(img, title: namesArray[indexPath.row], time: timesArray[indexPath.row], place: placesArray[indexPath.row])
return cell
} else {
return PreviewCell()
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return namesArray.count
}
func addNewEvent(name: String, image: String, time: String, place: String)
{
namesArray.append(name)
imagesArray.append(image)
timesArray.append(time)
placesArray.append(place)
}
You are already getting the number in to the arrays so what you need to do is just reload the tableview after the for loop.
//end of for-loop
self.tableView.reloadData()
The reason for this is the asynchronous execution of the request.startWithCompletionHandler. The code inside that block will most likely execute after your tableView already loaded and it therefor needs a reload after the data has been fetched
In case if you need to return data from closure you can define completion on your getData() method like this
func getData(completion:([DataType]) -> Void) {
//process data
let dataArray:DataType = []
completion(dataArray)
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
getData { (completionData) -> Void in
// process returned data
}
}
Hope this helps

How to load tableview before view is called?

I want to put the table names of my friends first. But why my view should be loaded first, then starts executing the code here
self.art = [responseObject]
let jsonArrays :[String:AnyObject] = self.art.firstObject as! Dictionary
let name = jsonArrays["response"]
for var value in name as! NSArray
{
value = (name?.valueForKey("first_name"))!
self.friends = [value]
}
Here is the full code
class TableViewController: UITableViewController
{
let manager = AFHTTPRequestOperationManager()
let url = "https://api.vk.com/method/friends.get"
var dict = NSDictionary()
var art = []
var friends = NSArray()
var arrayUser = NSArray()
var ar = []
override func viewDidLoad() {
super.viewDidLoad()
self.getFriends()
self.friends = NSArray()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getFriends()
{
dict = ["user_id":"107487867",
"name":"order",
"count":5,
"fields":"photo",]
self.manager.GET(url, parameters: dict,
success:{ (operation:AFHTTPRequestOperation,
responseObject: AnyObject!) in
self.art = [responseObject]
let jsonArrays :[String:AnyObject] = self.art.firstObject as! Dictionary
let name = jsonArrays["response"]
for var value in name as! NSArray
{
value = (name?.valueForKey("first_name"))!
self.friends = [value]
}
}){ (operation:AFHTTPRequestOperation!, NSError) -> Void in
}
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return friends.count
}

Keep getting a fatal error that says "unexpectedly found nil while unwrapping an Optional value" in iOS

I run my code on Xcode and it build fine but when I tap a button to change views it crashes with this error.
var selectedAccount : ACAccount!
var tweets : NSMutableArray?
var imageCache : NSCache?
var queue : NSOperationQueue?
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = selectedAccount.accountDescription
queue = NSOperationQueue()
queue!.maxConcurrentOperationCount = 4
func retrieveTweets() {
tweets?.removeAllObjects()
if let account = selectedAccount {
let requestURL = NSURL(string: "https://api.twitter.com/1.1/statuses/home_timeline.json")
let request = SLRequest(forServiceType: SLServiceTypeTwitter, requestMethod: SLRequestMethod.GET, URL: requestURL, parameters: nil)
request.account = account
request.performRequestWithHandler()
{
responseData, urlResponse, error in
if(urlResponse.statusCode == 200)
{
var jsonParseError : NSError?
self.tweets = NSJSONSerialization.JSONObjectWithData(responseData, options: NSJSONReadingOptions.MutableContainers, error: &jsonParseError) as? NSMutableArray
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
if let tweetCount = self.tweets?.count {
return tweetCount
}
else
{
return 0
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("TweetCell", forIndexPath: indexPath) as TweetCell
return cell
}
When it crashes it it posts an green line over the line "self.navigationItem.title = selectedAccount.accountDescription"
I'm not sure why its saying its associated with this line.
Please help
SC
Make sure you remove any warning messages here.

Resources