call deleteRowsAtIndexPaths multiple times - ios

There are several questions about this problem. I have tried all of the suggested answers but nothing has worked yet.
So I have this func which decline offers that a user receives. I can decline the offers and delete the cell rows but when there is only one cell left I get fatal error: Index out of range
func declineButtonTapped(sender: AnyObject) {
self.view.userInteractionEnabled = false
let buttonRow = sender.tag // this is the tag from my custom cell button
let offer = offers[buttonRow] // I get the error here
let loadingNotification = MBProgressHUD.showHUDAddedTo(self.view, animated: true)
loadingNotification.mode = MBProgressHUDMode.Indeterminate
loadingNotification.labelText = "declining offer...."
let myUrl = NSURL(string: "\(ipAddress)/api/v1.0/offers.php")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let postString = "id=\(offer.id!)&action=decline&offer_id=\(offer.offer_id!)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{ data, response, error in
if error != nil {
let messageToDisplay = error
self.view.userInteractionEnabled = true
return
}
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if let parseJSON = json{
let resultValue = parseJSON["status"] as? String
if resultValue == "Success"{
dispatch_async(dispatch_get_main_queue()) {
print("before count is \(self.offers.count)") // before the error the count is 2 here
self.offers.removeAtIndex(buttonRow) //update my model
self.tableView.deleteRowsAtIndexPaths([NSIndexPath(forRow: buttonRow, inSection: 0)], withRowAnimation: UITableViewRowAnimation.Fade)
print("after count is \(self.offers.count)") //then the count is 1 here
MBProgressHUD.hideAllHUDsForView(self.view, animated: true)
self.view.userInteractionEnabled = true
}
}else{
//no success
}
}
} catch{
}
}
task.resume()
}
inside cellForRowAtIndexPath I assign the tag value of the button
offerCell.declineButton.tag = indexPath.row
offerCell.declineButton.addTarget(self, action: #selector(OpenDealsDetailsViewController.declineButtonTapped(_:)), forControlEvents: UIControlEvents.TouchUpInside)
******UPDATE*****
I think I found the error. When I print
print("button row is\(buttonRow)") the number don't get updated. So the first time it calls the correct row but the second times it keep the indexPath.row it had when declineButtonTapped was called the first time
button row is0
before count is 2
after count is 1
button row is1 // this of course should be 0 as there is only one cell left
fatal error: Index out of range
if I try to do
self.offers.removeAtIndex(buttonRow)
self.tableView.deleteRowsAtIndexPaths([NSIndexPath(forRow: buttonRow, inSection: 0)], withRowAnimation: UITableViewRowAnimation.Fade)
self.tableView.reloadData()
I get the following error:
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).

You either shouldn't use tags or you should reload the table view fully after each change. Alternately you could iterate the visible cells and update their tag values.
If you were to always and only delete the last row from the table it'd be fine. As soon as you delete an earlier row all the rows after that now have an incorrect tag value. So, when you go to the last row it doesn't actually exist at that tag, and any other invalid rows will result in you deleting the wrong item from the server.
A better approach is to pass the cell an instance of a class which can action the deletion and call back to the view controller with details of the update made. The view controller can then update its data source and the table view. In this way you separate the table index path from the action you're going to take on the data.

Related

.reloadData() without reCreating visible cells or those who are in memory?

When I have instantiated the third cell, I will add more to my items to my model array and then I will update the collection view data with:
DispatchQueue.main.async(execute: {
self.collectionView.reloadData()
})
Everything works as expected. However, when I reload the data for my collectionView, it will instantiate cells that are currently visible or hold in memory (2,3). Unfortunately, I have some expensive server requests which consume a lot of time.
Instaniated 0
Instaniated 2
Instaniated 3
******polluting more data: size of cells 10
Instaniated 2
Instaniated 3
Instaniated 4
How can I reload the data without reCreating visible cells or those who are in memory?
Thanks a lot.
Instead of reloading the cells, try inserting or reloading the once that have actually changed. You can use UIColletionViews performBatchUpdates(_:) for this: Link
An example:
collectionView.performBatchUpdates {
self.collectionView.insertItems(at: [IndexPath(row: 1, section: 1)])
}
This ensures that only the new cells are loaded. You can also move around cells and sections in this method and even delete cells. The linked page contains documentation for all of this.
Why can't you go with below approach
1) I hope you have declared dataSource and collectionView objects as global to the class
let collectionView = UICollectionView()
var dataSource = [Any]()
2) Have one function to get the initial results from the API response
func getInitialPosts(){
// call api
// store your initial response in the local array object and reload collectionview
let results:[Any] = {response from the server call}
self.dataSource.append(contentsOf: results)
DispatchQueue.main.async(execute: {
self.collectionView.reloadData()
})
}
3) For the next call, you can have another function
func getPostsForPage(page:Int){
// call api with page number
let newResults = {response from the server call}
self.dataSource.append(contentsOf: newResults)
var indexPathsToReload = [IndexPath]()
let section = 0
var row = self.dataSource.count - 1
//add new data from server response
for _ in newResults {
let indexPath = IndexPath(row: row, section: section)
row+=1
indexPathsToReload.append(indexPath)
}
// perform reload action
DispatchQueue.main.async(execute: {
self.collectionView.insertItems(at: indexPathsToReload)
})
}
Suppose from your network adapter you are calling delegate function fetchData with new data. Here you have to check if your data is empty or not to check if you need to add new data, or reload entire CollectionView.
Then you create all indexPaths that you need to fetch more, in order to let already fetched cell stay as they are. And finally use insertItems(at: IndexPaths).
I use page in order to paginate new data with page number in the future. Strictly for my use case. Good luck!
func fetchData(with videos: [VideoModel], page: Int) {
guard self.data.count == 0 else{
self.addNewData(with: videos, page: page)
return
}
self.data = videos
DispatchQueue.main.async {
self.isPaging = false
self.collectionView?.reloadData()
self.page = page
}
}
func addNewData(with videos: [VideoModel], page: Int){
var indexPathsToReload = [IndexPath]()
let section = 0
var row = self.data.count - 1
self.data += videos
for _ in videos {
print(row)
let indexPath = IndexPath(row: row, section: section)
row+=1
indexPathsToReload.append(indexPath)
}
DispatchQueue.main.async{
self.isPaging = false
self.collectionView!.insertItems(at: indexPathsToReload)
self.page = page
}
}

Swift UItableview with AlamofireImage crash when scrolling fast

Im using AlamofireImage to load images in an async way.
It works quite well except when I scroll very fast the app crashes.
I assume it is because when maybe more than 10 requests are being sent in a very short period of time the app crashes (when I scroll fast).
I also see a sudden spike in memory usage.
When I scroll slowly and maybe 4 requests are sent in a short period it does not crash.
Does anyone have a hint on how to prevent this? How can I cancel requests of invisible cells where the user has been scrolled by?
Here is the code:
// Dequeue your cell and other code goes here.
// with as! the cell is set to the custom cell class: DemoCell
// afterwards all data can be loaded from the JSON response into the cells
override func tableView(tableView: UITableView, cellForRowAtIndexPath
indexPath: NSIndexPath) -> UITableViewCell {
let cell =
tableView.dequeueReusableCellWithIdentifier("FoldingCell",
forIndexPath: indexPath) as! DemoCell
cell.delegate = self
//tag the cell with the indexpath row number to make sure the loaded asynch image corresponds to the right cell
cell.tag = indexPath.row
//clear cell of eventually reused images
cell.schoolCoverImage.image = UIImage()
cell.schoolBiggerImage.image = UIImage()
//TODO: set all custom cell properties here (retrieve JSON and set in cell), use indexPath.row as arraypointer
let resultList = self.items["result"] as! [[String: AnyObject]]
let itemForThisRow = resultList[indexPath.row]
cell.schoolNameClosedCell.text = itemForThisRow["name"] as! String
cell.schoolNameOpenedCell.text = itemForThisRow["name"] as! String
self.schoolIdHelperField = itemForThisRow["name"] as! String
cell.schoolIntroText.text = itemForThisRow["name"] as! String
// set the button's tag like below.
cell.innerCellButton.tag = indexPath.row
//call method when button inside cell is tapped
cell.innerCellButton.addTarget(self, action: #selector(MainTableViewController.cellButtonTapped(_:)), forControlEvents: .TouchUpInside)
cell.schoolIntroText.text = "We from xx University..."
//handle the image from a separate API call
let schoolIdNumber = itemForThisRow["sco_id"] as! NSInteger
let schoolIdString = String(schoolIdNumber)
//TOCHeck: maybe Id is not correct and should be replaced by indexCount
let imageNameString = itemForThisRow["image"] as! String
//only load the image of the cell which is visible in the screen
// print("current cells visible?")
// print(tableView.visibleCells)
// print("currentCell")
// print(cell.tag)
// if(tableView.visibleCells.contains(cell)) {
let urlRequest = NSURLRequest(URL: NSURL(string: "https://ol-web- test.herokuapp.com/olweb/api/v1/schools/"+schoolIdString+"/image/"+imageNameString)!)
print(urlRequest)
//does cell number/tag match current indexpath row?
if(cell.tag == indexPath.row) {
//use cache in case image has been saved to cache already, otherwise get image from networking
if(self.photoCache.imageForRequest(urlRequest) != nil) {
cell.schoolCoverImage.image = photoCache.imageForRequest(urlRequest)
cell.schoolBiggerImage.image = photoCache.imageForRequest(urlRequest)
print("image from cache loaded")
}
else
{
self.imageDownloader.downloadImage(URLRequest: urlRequest) { response in
print(response.request)
print(response.response)
debugPrint(response.result)
if let image = response.result.value {
print("here comes the printed image:: ")
print(image)
print(schoolIdString)
//set image to the cell
cell.schoolCoverImage.image = image
cell.schoolBiggerImage.image = image
self.photoCache.addImage(image, forRequest: urlRequest)
print("image from network loaded and added to cache")
print(self.photoCache.memoryCapacity.description)
print(self.photoCache.memoryUsage.description)
}
}
}
}
return cell
}
EDIT: Log error is a NullPointer
30/image/Beet_Language_Bournemouth_1.jpeg }
fatal error: unexpectedly found nil while unwrapping an Optional va lue
Code line:
let urlRequest = NSURLRequest(URL: NSURL(string: "https://ol-web- test.herokuapp.com/olweb/api/v1/schools/"+schoolIdString+"/image/"+imageNameString)!)
I load here the params schoolIdString and imageNameString from a previous query.
Thx for the answers. It was corrupt data from the database which made the URL corrupt

how to set value for perticular index in CoreData. iOS Swift

In my app I have used core data and on button press of uitableview cell I delete or pin unpin the value.
So on the click of button, I want to set value of that index.
Here is my code:
in cellforrow at index path method
cell.pinButton.tag = indexPath.row
cell.pinButton.addTarget(self, action: #selector(MessageViewController.buttonDeletePressed(_:)), forControlEvents: UIControlEvents.TouchUpInside)
cell.btnpinUnpin.tag = indexPath.row
cell.btnpinUnpin.addTarget(self, action: #selector(MessageViewController.buttonPinPressed(_:)), forControlEvents: UIControlEvents.TouchUpInside)
and these are function
func buttonDeletePressed(sender:UIButton) {
// let index = sender.tag
// print(index)
// let feedId = person?.valueForKey("feed_id")?.objectAtIndex(index)
// deleteFeed(feedId! as! String)
let index = sender.tag
// print(index)
moc.deleteObject(people[index] as NSManagedObject)
people.removeAtIndex(index)
let _ : NSError! = nil
do {
try moc.save()
self.feedTable.reloadData()
} catch {
print("error : \(error)")
}
}
func buttonPinPressed(sender:UIButton) {
// let index = sender.tag
// print(index)
// let feedId = person?.valueForKey("feed_id")?.objectAtIndex(index)
// deleteFeed(feedId! as! String)
let index = sender.tag
// print(index)
// moc.deleteObject(people[index] as NSManagedObject)
if (person?.valueForKey("isPin") as! String == "1")
{
person?.setValue("0", forKey: "isPin")
}
else
{
person?.setValue("1", forKey: "isPin")
}
// people.removeAtIndex(index)
let _ : NSError! = nil
do {
try moc.save()
self.feedTable.reloadData()
} catch {
print("error : \(error)")
}
}
By this I can delete whole object correctly. But when I tape on pin button every time its selecting last value. Reason is that I can not set index for that nsmanagedobject. So how can I do this?
You're missing person = people[index]
But, your real issue is that you're using tags and this forces you to reload the table all the time, because otherwise a lot of the tags are wrong after a delete.
It's also recommended to use an FRC as the data source, then you can animate your updates.
In order to achieve that you'd create a custom cell class so you can pass it something better than a tag value. That might be the managed object itself (not ideal), the object is for the managed object (better), or a different class, like a view model, which knows what to do when the button is pressed (and could provide data for the cell to display too) (best).

Casting of a custom class cell for UIViewTable fails with optional unwrap error

I got UITableView with two types of cells. The first type presents existing data, the second is used to add new items to the table. So I created a subclass "AddListTableViewCell" and put in "#IBOutlet weak var addListTextBox: UITextField!" property to read it's contents.
This "Add List" cell was drawn in the first row with no runtime errors. It was pushed by:
#IBAction func AddListButtonPressed(sender: UIBarButtonItem) {
if !isAddingList {
isAddingList = true
ListsTableView.reloadData()
let path = NSIndexPath(forRow: 0, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(path) as? AddListTableViewCell
cell.addListTextBox.becomeFirstResponder()
}
}
}
On ListsTableView.reloadData() method "tableView(_:cellForRowAtIndexPath:" has created additional cell. Again: no errors.
Then I changed it's order wishing it to be presented at the end of the table and added more demo items to observe it's interaction (forRow in AddListButtonPressed changed too :).
Now when I ran the app and pressed AddListButton, that fires func AddListButtonPressed, I got "fatal error: unexpectedly found nil while unwrapping an Optional value" with "let cell = tableView.cellForRowAtIndexPath(path) as? AddListTableViewCell".
Futhermore, if view was scrolled after the app starts, there are no errors, but warnig "[UIWindow endDisablingInterfaceAutorotationAnimated:] called on > without matching -beginDisablingInterfaceAutorotation. Ignoring." in the console.
I found a solution on this site to replace faulty line
let cell = tableView.cellForRowAtIndexPath(path) as? AddListTableViewCell
with
let cell = tableView.dequeueReusableCellWithIdentifier("AddList", forIndexPath: path) as! AddListTableViewCell
and it works well but I still generates a warning.
But why am I supposed to create cell again, when it's already set with "tableView(_:cellForRowAtIndexPath:" method upon "ListsTableView.reloadData()"? Is it possible to somehow keep "let cell = tableView.cellForRowAtIndexPath(path) as? AddListTableViewCell" to avoid warnings?
EDIT One more function, where it's used (sorry for no indention, posted from phone):
private func addList () {
let path = NSIndexPath(forRow: brain.tree.count, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(path) as! AddListTableViewCell
if let listName = cell.addListTextBox.text {
if listName.characters.filter({!" ".characters.contains($0)}).count > 0 {
brain.newList(listName)
cell.addListTextBox.text = ""
isAddingList = false
ListsTableView?.reloadData()
performSegueWithIdentifier("ShowTasksSegue", sender: nil)
}
}
}

Swift updating UITableView with new data

I'm trying to repopulate my UITableView with data from another JSON call.
However my current setup doesn't seem to work, and while there are many identical questions on SO the answers I could find I've already tried.
I'm saving my API data in CoreData entity objects. And I'm filling my UITableView with my CoreData entities.
In my current setup I have 3 different API Calls that has a different amount of data, and of course different values. I need to be able to switch between these 3 datasets, and that's what I'm trying to accomplish now. (so far without progress).
I have a function called "loadSuggestions", which is where I assume my fault lies.
First I check for an internet connection.
I set the managedObjectContext
I check what API I need to call (This is determined before the function is called, and I checked that it works as intended)
I delete all the current data from the entity that it's trying to call. (I also tried to delete the data from the last data the UITableView had loaded. That didn't change anything). I also checked that this works. After deleting the data, I checked that it prints out an empty array, I also tried logging the objects it deletes to make sure.
I then fetch the new data, save it into temporary variables. Then save it to my core data.
Then I make my second API call (dependant on a variable from the first one), fetch that data and save it the same way.
I append the object to the array the UITableView fills it's cells from. (I checked that it prints out correctly as well)
And lastly I reload the tableView. (doesn't change a thing)
Here's the function:
func loadSuggestions() {
println("----- Loading Data -----")
// Check for an internet connection.
if Reachability.isConnectedToNetwork() == false {
println("ERROR: -> No Internet Connection <-")
} else {
// Set the managedContext again.
managedContext = appDelegate.managedObjectContext!
// Check what API to get the data from
if Formula == 0 {
formulaEntity = "TrialFormulaStock"
println("Setting Entity: \(formulaEntity)")
formulaAPI = NSURL(string: "http://api.com/json/entry_weekly.json")
} else if Formula == 1 {
formulaEntity = "ProFormulaStock"
println("Setting Entity: \(formulaEntity)")
formulaAPI = NSURL(string: "http://api.com/json/entry_weekly.json")
} else if Formula == 2 {
formulaEntity = "PremiumFormulaStock"
formulaAPI = NSURL(string: "http://api.com/json/proff_weekly.json")
println("Setting Entity: \(formulaEntity)")
} else if Formula == 3 {
formulaEntity = "PlatinumFormulaStock"
println("Setting Entity: \(formulaEntity)")
formulaAPI = NSURL(string: "http://api.com/json/fund_weekly.json")
}
// Delete all the current objects in the dataset
let fetchRequest = NSFetchRequest(entityName: formulaEntity)
let a = managedContext.executeFetchRequest(fetchRequest, error: nil) as! [NSManagedObject]
for mo in a {
managedContext.deleteObject(mo)
}
// Removing them from the array
stocks.removeAll(keepCapacity: false)
// Saving the now empty context.
managedContext.save(nil)
// Set up a fetch request for the API data
let entity = NSEntityDescription.entityForName(formulaEntity, inManagedObjectContext:managedContext)
var request = NSURLRequest(URL: formulaAPI!)
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
var formula = JSON(data: data!)
// Loop through the api data.
for (index: String, actionable: JSON) in formula["actionable"] {
// Save the data into temporary variables
stockName = actionable["name"].stringValue
ticker = actionable["ticker"].stringValue
action = actionable["action"].stringValue
suggestedPrice = actionable["suggested_price"].floatValue
weight = actionable["percentage_weight"].floatValue
// Set up CoreData for inserting a new object.
let stock = NSManagedObject(entity: entity!,insertIntoManagedObjectContext:managedContext)
// Save the temporary variables into coreData
stock.setValue(stockName, forKey: "name")
stock.setValue(ticker, forKey: "ticker")
stock.setValue(action, forKey: "action")
stock.setValue(suggestedPrice, forKey: "suggestedPrice")
stock.setValue(weight, forKey: "weight")
// Get ready for second API call.
var quoteAPI = NSURL(string: "http://dev.markitondemand.com/Api/v2/Quote/json?symbol=\(ticker)")
// Second API fetch.
var quoteRequest = NSURLRequest(URL: quoteAPI!)
var quoteData = NSURLConnection.sendSynchronousRequest(quoteRequest, returningResponse: nil, error: nil)
if quoteData != nil {
// Save the data from second API call to temporary variables
var quote = JSON(data: quoteData!)
betterStockName = quote["Name"].stringValue
lastPrice = quote["LastPrice"].floatValue
// The second API call doesn't always find something, so checking if it exists is important.
if betterStockName != "" {
stock.setValue(betterStockName, forKey: "name")
}
// This can simply be set, because it will be 0 if not found.
stock.setValue(lastPrice, forKey: "lastPrice")
} else {
println("ERROR ----------------- NO DATA for \(ticker) --------------")
}
// Error handling
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
// Append the object to the array. Which fills the UITableView
stocks.append(stock)
}
// Reload the tableview with the new data.
self.tableView.reloadData()
}
}
Currently, when I push to this viewController, this function is called in viewDidAppear like so:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
tableView.allowsSelection = true
if isFirstTime {
loadSuggestions()
isFirstTime = false
}
}
It populates the tableView correctly and everything seems to work as planned.
However if I open my slide-out menu and call a function to load different data, nothing happens, here's an example function:
func platinumFormulaTapGesture() {
// Menu related actions
selectView(platinumFormulaView)
selectedMenuItem = 2
// Setting the data to load
Formula = 3
// Sets the viewController. (this will mostly be the same ViewController)
menuTabBarController.selectedIndex = 0
// Set the new title
navigationController?.navigationBar.topItem!.title = "PLATINUM FORMULA"
// And here I call the loadSuggestions function again. (this does run)
SuggestionsViewController().loadSuggestions()
}
Here's the 2 relevant tableView functions:
number of Rows:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return stocks.count
}
And cellForRowAtIndexPath, (this is where I set up my cells with the CoreData)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("com.mySuggestionsCell", forIndexPath: indexPath) as! mySuggestionsCell
let formulaStock = stocks[indexPath.row]
cell.stockNameLabel.text = formulaStock.valueForKey("name") as! String!
cell.tickerLabel.text = formulaStock.valueForKey("ticker") as! String!
action = formulaStock.valueForKey("action") as! String!
suggestedPrice = formulaStock.valueForKey("suggestedPrice") as! Float
let suggestedPriceString = "Suggested Price\n$\(suggestedPrice.roundTo(2))" as NSString
var suggestedAttributedString = NSMutableAttributedString(string: suggestedPriceString as String)
suggestedAttributedString.addAttributes(GrayLatoRegularAttribute, range: suggestedPriceString.rangeOfString("Suggested Price\n"))
suggestedAttributedString.addAttributes(BlueHalisRBoldAttribute, range: suggestedPriceString.rangeOfString("$\(suggestedPrice.roundTo(2))"))
cell.suggestedPriceLabel.attributedText = suggestedAttributedString
if action == "SELL" {
cell.suggestionContainer.backgroundColor = UIColor.formulaGreenColor()
}
if let lastPrice = formulaStock.valueForKey("lastPrice") as? Float {
var lastPriceString = "Last Price\n$\(lastPrice.roundTo(2))" as NSString
var lastAttributedString = NSMutableAttributedString(string: lastPriceString as String)
lastAttributedString.addAttributes(GrayLatoRegularAttribute, range: lastPriceString.rangeOfString("Last Price\n"))
percentDifference = ((lastPrice/suggestedPrice)*100.00)-100
if percentDifference > 0 && action == "BUY" {
lastAttributedString.addAttributes(RedHalisRBoldAttribute, range: lastPriceString.rangeOfString("$\(lastPrice.roundTo(2))"))
} else if percentDifference <= 0 && percentDifference > -100 && action == "BUY" {
lastAttributedString.addAttributes(GreenHalisRBoldAttribute, range: lastPriceString.rangeOfString("$\(lastPrice.roundTo(2))"))
} else if percentDifference <= 0 && percentDifference > -100 && action == "SELL" {
lastAttributedString.addAttributes(RedHalisRBoldAttribute, range: lastPriceString.rangeOfString("$\(lastPrice.roundTo(2))"))
} else if percentDifference == -100 {
lastPriceString = "Last Price\nN/A" as NSString
lastAttributedString = NSMutableAttributedString(string: lastPriceString as String)
lastAttributedString.addAttributes(GrayLatoRegularAttribute, range: lastPriceString.rangeOfString("Last Price\n"))
lastAttributedString.addAttributes(BlackHalisRBoldAttribute, range: lastPriceString.rangeOfString("N/A"))
}
cell.lastPriceLabel.attributedText = lastAttributedString
} else {
println("lastPrice nil")
}
weight = formulaStock.valueForKey("weight") as! Float
cell.circleChart.percentFill = weight
let circleChartString = "\(weight.roundTo(2))%\nWEIGHT" as NSString
var circleChartAttributedString = NSMutableAttributedString(string: circleChartString as String)
circleChartAttributedString.addAttributes(BlueMediumHalisRBoldAttribute, range: circleChartString.rangeOfString("\(weight.roundTo(2))%\n"))
circleChartAttributedString.addAttributes(BlackSmallHalisRBoldAttribute, range: circleChartString.rangeOfString("WEIGHT"))
cell.circleChartLabel.attributedText = circleChartAttributedString
cell.selectionStyle = UITableViewCellSelectionStyle.None
return cell
}
I define my appDelegate as the very first thing in my class:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
var managedContext = NSManagedObjectContext()
I think that's all the code that could possibly be the cause of the bug. Again I think the most likely cause would be in the loadSuggestions function.
To force update the tableView I also tried calling setNeedsDisplay and setNeedsLayout both on self.view and tableView, neither of which seemed to do anything at all.
Any advice in figuring out why this tableView refuses to update would be an enormous help!
And I apologize for the walls of code, but I havn't been able to find the exact origin of the issue.
This line in the platinumFormulaTapGesture function is incorrect,
SuggestionsViewController().loadSuggestions()
This creates a new instance of SuggestionsViewController, which is not the one you have on screen. You need to get a pointer to the one you have. How you do that depends on your controller hierarchy, which you haven't explained fully enough.

Resources