Swift – Table View reloadData not working after editing contents of cell - ios

In my app, I'm showing user a table view of entries and when they tap on one, they're taken to a screen with a TextView so they can edit the contents of that cell. When they save, they're transitioned back to the tableView. The problem is that the data isn't reloading when they return to the tableView, it shows the same data as before they edited the contents of a cell
I've tried putting self.tableView.reloadData() in both viewWillAppear and viewDidAppear but neither are working. I've read a bunch of answers pertaining to this and none have worked. I'd love your help. Thanks!
PastSessionsViewController.swift
class PastSessionsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var arrayOfEntriesNew: [Entry] = [Entry]()
let transitionManager = TransitionManager()
var entry: String?
var entryDate: NSDate?
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let gradient: CAGradientLayer = CAGradientLayer()
let arrayColors: [AnyObject] = [
UIColor(red: 0.302, green: 0.612, blue: 0.961, alpha: 1.000).CGColor,
UIColor(red: 0.247, green: 0.737, blue: 0.984, alpha: 1.000).CGColor
]
tableView.backgroundColor = nil
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 168.0
gradient.frame = view.bounds
gradient.colors = arrayColors
view.layer.insertSublayer(gradient, atIndex: 0)
prepareEntries()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
self.tableView.reloadData()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
func prepareEntries() {
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
let managedObjectContext = appDelegate.managedObjectContext!
let request = NSFetchRequest(entityName: "Meditation")
let sortDescriptor = NSSortDescriptor(key: "date", ascending: false)
request.sortDescriptors = [sortDescriptor]
var error: NSError?
var showStreak = (top: false, bottom: false)
let result = managedObjectContext.executeFetchRequest(request, error: &error)
if let objects = result as? [Meditation] {
for (index, object) in enumerate(objects) {
var timeLabel = lengthMinutesLabel(minutesString: lengthMinutes(object.length))
var entry = Entry(sessionLength: lengthMinutes(object.length), sessionTimeUnit: timeLabel, sessionStartTime: "\(object.date.format())", sessionJournalEntry: object.journalEntry, sessionStreakTop: showStreak.top, sessionStreakBottom: showStreak.bottom)
arrayOfEntriesNew.append(entry)
}
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfEntriesNew.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: EntryCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as EntryCell
let entry = arrayOfEntriesNew[indexPath.row]
var journalEntry = entry.sessionJournalEntry
cell.sessionStartTimeLabel.text = entry.sessionStartTime
cell.sessionJournalEntryLabel.text = journalEntry
cell.sessionLengthLabel.text = entry.sessionLength
cell.sessionTimeUnitLabel.text = entry.sessionTimeUnit
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// janky but works, probably a better way to do this. Will figure it out after v1
if sender is UIButton {
let destinationVC = segue.destinationViewController as ViewController
destinationVC.showJournalButton = false
} else {
let path = self.tableView.indexPathForSelectedRow()!
let location = path.row
let appDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
let managedObjectContext = appDelegate.managedObjectContext!
let request = NSFetchRequest(entityName: "Meditation")
let sortDescriptor = NSSortDescriptor(key: "date", ascending: false)
request.sortDescriptors = [sortDescriptor]
var error: NSError?
let result = managedObjectContext.executeFetchRequest(request, error: &error)
if let objects = result as? [Meditation] {
var journalVC = segue.destinationViewController as EditJournalViewController
journalVC.journalEntryCoreDataLocation = path.row
journalVC.journalEntryToEdit = objects[location].journalEntry
journalVC.journalEntryToEditTimestamp = objects[location].date
let transitionManager = self.transitionManager
transitionManager.presenting = true
transitionManager.direction = "left"
journalVC.transitioningDelegate = transitionManager
}
}
}
}

add prepareEntries() in viewWillAppear

Related

Table view scrolling is erratic and jumpy even though I reuse cells?

Okay, so I'm not sure whats been happening with my Table view, but it seems to act a bit strange now that I load images from parse onto it. At first, it ran smoothly, but now that I'm working in ios 9, the scrolling is horrible
Optimizations I've used to reduce this(Keep in mind they do not really help.)
-Removed transparent objects and set them to default background
-reused table cells
-Tried to use lower quality images
Here is my code
import UIKit
class mainVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var resultsTable: UITableView!
#IBOutlet weak var menuButton:UIBarButtonItem!
var deleteArray = [String]()
var followArray = [String]()
var resultsLocationArray = [String]()
var datetextfielArray = [String]()
var imageDates = [String]()
var resultsNameArray = [String]()
var resulltsImageFiles = [PFFile]()
var resultsTweetArray = [String]()
var resultsHasImageArray = [String]()
var resultsTweetImageFiles = [PFFile?]()
var refresher:UIRefreshControl!
override func viewDidLoad() {
super.viewDidLoad()
if self.revealViewController() != nil {
menuButton.target = self.revealViewController()
menuButton.action = "revealToggle:"
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
// Uncomment to change the width of menu
//self.revealViewController().rearViewRevealWidth = 62
}
let theWidth = view.frame.size.width
let theHeight = view.frame.size.height
resultsTable.frame = CGRectMake(0, 0, theWidth, theHeight)
let tweetBtn = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Compose, target: self, action: Selector("tweetBtn_click"))
let searchBtn = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Search, target: self, action: Selector("searchBtn_click"))
let buttonArray = NSArray(objects: tweetBtn, searchBtn)
self.navigationItem.rightBarButtonItems = buttonArray as? [UIBarButtonItem]
refresher = UIRefreshControl()
refresher.tintColor = UIColor.blackColor()
refresher.addTarget(self, action: "refresh", forControlEvents: UIControlEvents.ValueChanged)
self.resultsTable.addSubview(refresher)
}
func refresh() {
print("refresh table")
refreshResults()
}
func refreshResults() {
followArray.removeAll(keepCapacity: false)
resultsNameArray.removeAll(keepCapacity: false)
resulltsImageFiles.removeAll(keepCapacity: false)
resultsTweetArray.removeAll(keepCapacity: false)
resultsLocationArray.removeAll(keepCapacity: false)
resultsHasImageArray.removeAll(keepCapacity: false)
resultsTweetImageFiles.removeAll(keepCapacity: false)
datetextfielArray.removeAll(keepCapacity: false)
let followQuery = PFQuery(className: "follow")
followQuery.whereKey("user", equalTo: PFUser.currentUser()!.username!)
followQuery.addDescendingOrder("createdAt")
let objects = followQuery.findObjects()
for object in objects! {
self.followArray.append(object.objectForKey("userToFollow") as! String)
}
let query:PFQuery = PFQuery(className: "tweets")
query.whereKey("userName", containedIn: followArray)
query.addDescendingOrder("createdAt")
query.findObjectsInBackgroundWithBlock {
(objects:[AnyObject]?, error:NSError?) -> Void in
if error == nil {
for object in objects! {
self.resultsNameArray.append(object.objectForKey("profileName") as! String)
self.resulltsImageFiles.append(object.objectForKey("photo") as! PFFile)
self.resultsTweetArray.append(object.objectForKey("tweet") as! String)
//resultsLocationArray
self.resultsLocationArray.append(object.objectForKey("tweetlocation") as! String)
self.resultsHasImageArray.append(object.objectForKey("hasImage") as! String)
self.resultsTweetImageFiles.append(object.objectForKey("tweetImage") as? PFFile)
self.datetextfielArray.append(object.objectForKey("datetextfield") as! String)
self.resultsTable.reloadData()
}
self.refresher.endRefreshing()
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
self.navigationController?.navigationBarHidden = false
super.viewWillAppear(animated)
let nav = self.navigationController?.navigationBar
nav?.barStyle = UIBarStyle.Black
nav?.tintColor = UIColor.whiteColor()
nav?.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
self.navigationItem.hidesBackButton = true
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
override func viewDidAppear(animated: Bool) {
refreshResults()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return resultsNameArray.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if resultsHasImageArray[indexPath.row] == "yes" {
return self.view.frame.size.width + 130
} else {
return 130
}
}
//var theDtS = dtFormater.stringFromDate(self.dateArray[i])
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:mainCell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! mainCell
cell.tweetImg.hidden = true
cell.locationTxt.text = self.resultsLocationArray[indexPath.row]
cell.profileLbl.text = self.resultsNameArray[indexPath.row]
cell.messageTxt.text = self.resultsTweetArray[indexPath.row]
cell.datetextfield.text = self.datetextfielArray[indexPath.row]
resulltsImageFiles[indexPath.row].getDataInBackgroundWithBlock {
(imageData:NSData?, error:NSError?) -> Void in
//resultsLocationArray
if error == nil {
let image = UIImage(data: imageData!)
cell.imgView.image = image
}
}
if resultsHasImageArray[indexPath.row] == "yes" {
let theWidth = view.frame.size.width
cell.tweetImg.frame = CGRectMake(0, 0, theWidth, theWidth)
cell.tweetImg.hidden = false
resultsTweetImageFiles[indexPath.row]?.getDataInBackgroundWithBlock({
(imageData:NSData?, error:NSError?) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
cell.tweetImg.image = image
}
})
}
return cell
}
func tweetBtn_click() {
print("tweet pressed")
self.performSegueWithIdentifier("gotoTweetVCFromMainVC", sender: self)
}
func searchBtn_click() {
print("search pressed")
self.performSegueWithIdentifier("gotoUsersVCFromMainVC", sender: self)
}
}

Collection views cells are not appearing in collection view?

This is my first time working with collection views and I am struggling quite a bit. I set up a collection view layout in the "setupView" function, and then implemented the typical view methods, like numberOfSections and cellForRowAtIndexPath. Right now, I'm just trying to get the collection view to work so I'm just using an image that I already have in my workspace, instead of getting pictures from an API (that will come later).
Here is the code I am using. Why is it not displaying anything other than a black screen ?
import UIKit
import Alamofire
import AlamofireImage
class PhotoBrowserCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let goldenWordsYellow = UIColor(red: 247.00/255.0, green: 192.00/255.0, blue: 51.00/255.0, alpha: 0.5)
#IBOutlet weak var menuButton:UIBarButtonItem!
#IBOutlet var picturesCollectionView: UICollectionView!
var pictureObjects = NSMutableOrderedSet(capacity: 1000)
var customRefreshControl = UIRefreshControl()
let PhotoBrowserCellIdentifier = "PhotoBrowserCell"
var dateFormatter = NSDateFormatter()
var nodeIDArray = NSMutableArray()
var timeStampDateString : String!
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.registerClass(PhotoBrowserCollectionViewCell.self, forCellWithReuseIdentifier: PhotoBrowserCellIdentifier)
self.revealViewController().rearViewRevealWidth = 280
collectionView!.delegate = self
collectionView!.dataSource = self
customRefreshControl = UIRefreshControl()
customRefreshControl.backgroundColor = goldenWordsYellow
customRefreshControl.tintColor = UIColor.whiteColor()
self.picturesCollectionView!.addSubview(customRefreshControl)
navigationController?.setNavigationBarHidden(false, animated: true)
navigationItem.title = "Pictures"
setupView()
populatePhotos()
self.dateFormatter.dateFormat = "dd/MM/yy"
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5 // setting an arbitrary value in case pictureObjects is not getting correctly populated
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(PhotoBrowserCellIdentifier, forIndexPath: indexPath) as! PhotoBrowserCollectionViewCell
cell.imageView.image = UIImage(named: "mail")
return cell
}
And here is my setupView function.
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("ShowPhoto", sender: (self.pictureObjects.objectAtIndex(indexPath.item) as! PictureElement).imageURL)
}
func setupView() {
navigationController?.setNavigationBarHidden(false, animated: true)
let layout = UICollectionViewFlowLayout()
let itemWidth = (view.bounds.size.width - 2) / 3
layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
layout.minimumInteritemSpacing = 1.0
layout.minimumLineSpacing = 1.0
collectionView!.collectionViewLayout = layout
navigationItem.title = "Pictures"
customRefreshControl.tintColor = UIColor.whiteColor()
customRefreshControl.addTarget(self, action: "handleRefresh", forControlEvents: .ValueChanged)
self.collectionView!.addSubview(customRefreshControl)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(120, 120)
}
Everything looks really messed up in the storyboard. I'm using a UICollectionViewController swift class (not a UIViewController + collectionView combo), and I don't really know which outlets I should be using. Here is my list of connections on the entire view controller:
And finally, here is my very simple view hierarchy.
I truly have no idea why the collection view isn't working properly. Any ideas ?
EDIT 1: I changed a lot of code and ended up getting my collectionView to work. For those who are struggling with a similar issue, here is the entirety of the code I am using for the collectionView. Maybe it will help you fix problems in your own collectionView code
import UIKit
import Alamofire
import AlamofireImage
class PhotoBrowserCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
let goldenWordsYellow = UIColor(red: 247.00/255.0, green: 192.00/255.0, blue: 51.00/255.0, alpha: 0.5)
#IBOutlet weak var menuButton:UIBarButtonItem!
#IBOutlet var picturesCollectionView: UICollectionView!
var temporaryPictureObjects = NSMutableOrderedSet(capacity: 1000)
var pictureObjects = NSMutableOrderedSet(capacity: 1000)
var goldenWordsRefreshControl = UIRefreshControl()
var revealViewControllerIndicator : Int = 0
let imageCache = NSCache()
var customView: UIView!
var labelsArray: [UILabel] = []
var isAnimating = false
var currentColorIndex = 0
var currentLabelIndex = 0
var timer : NSTimer!
var populatingPhotos = false
var currentPage = 0
let PhotoBrowserCellIdentifier = "PhotoBrowserCell"
var dateFormatter = NSDateFormatter()
var nodeIDArray = NSMutableArray()
var timeStampDateString : String!
var cellLoadingIndicator = UIActivityIndicatorView()
var scrollViewDidScrollLoadingIndicator = UIActivityIndicatorView()
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.registerClass(PhotoBrowserCollectionViewCell.self, forCellWithReuseIdentifier: PhotoBrowserCellIdentifier)
self.cellLoadingIndicator.backgroundColor = goldenWordsYellow
self.cellLoadingIndicator.hidesWhenStopped = true
if self.revealViewController() != nil {
revealViewControllerIndicator = 1
menuButton.target = self.revealViewController()
menuButton.action = "revealToggle:"
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
self.revealViewController().rearViewRevealWidth = 280
collectionView!.delegate = self
collectionView!.dataSource = self
goldenWordsRefreshControl = UIRefreshControl()
goldenWordsRefreshControl.backgroundColor = goldenWordsYellow
goldenWordsRefreshControl.tintColor = UIColor.whiteColor()
self.collectionView!.addSubview(goldenWordsRefreshControl)
navigationController?.setNavigationBarHidden(false, animated: true)
navigationItem.title = "Pictures"
setupView()
populatePhotos()
self.dateFormatter.dateFormat = "dd/MM/yy"
self.cellLoadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
self.cellLoadingIndicator.color = goldenWordsYellow
self.cellLoadingIndicator.center = (self.collectionView?.center)!
self.collectionView!.addSubview(cellLoadingIndicator)
self.collectionView!.bringSubviewToFront(cellLoadingIndicator)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if goldenWordsRefreshControl.refreshing {
if !isAnimating {
holdRefreshControl()
}
}
}
func holdRefreshControl() {
timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: "handleRefresh", userInfo: nil, repeats: true)
}
override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return (pictureObjects.count) // setting an arbitrary value in case pictureObjects is not getting correctly populated
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(PhotoBrowserCellIdentifier, forIndexPath: indexPath) as! PhotoBrowserCollectionViewCell
if let pictureObject = pictureObjects.objectAtIndex(indexPath.row) as? PictureElement {
let title = pictureObject.title ?? "" // if pictureObject.title == nil, then we return an empty string
let timeStampDateObject = NSDate(timeIntervalSince1970: NSTimeInterval(pictureObject.timeStamp))
let timeStampDateString = dateFormatter.stringFromDate(timeStampDateObject)
let author = pictureObject.author ?? ""
let issueNumber = pictureObject.issueNumber ?? ""
let volumeNumber = pictureObject.volumeNumber ?? ""
let nodeID = pictureObject.nodeID ?? 0
let imageURL = pictureObject.imageURL ?? "http://goldenwords.ca/sites/all/themes/custom/gw/logo.png"
cell.request?.cancel()
if let image = self.imageCache.objectForKey(imageURL) as? UIImage {
cell.imageView.image = image
} else {
cell.imageView.image = nil
cell.request = Alamofire.request(.GET, imageURL).responseImage() { response in
if let image = response.result.value {
self.imageCache.setObject(response.result.value!, forKey: imageURL)
if cell.imageView.image == nil {
cell.imageView.image = image
}
}
}
}
}
return cell
}
self.performSegueWithIdentifier("ShowPhoto", sender: self)
}
func setupView() {
navigationController?.setNavigationBarHidden(false, animated: true)
let layout = UICollectionViewFlowLayout()
let itemWidth = (view.bounds.size.width) / 3
layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
layout.minimumInteritemSpacing = 1.0
layout.minimumLineSpacing = 1.0
collectionView!.collectionViewLayout = layout
navigationItem.title = "Pictures"
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(((self.collectionView?.frame.width)!*0.5)-2, self.collectionView!.frame.height/3)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowPhoto" {
let detailViewController = segue.destinationViewController as! PhotoViewerViewController
let indexPaths = self.collectionView!.indexPathsForSelectedItems()
let indexPath = indexPaths![0] as! NSIndexPath
let item = indexPath.item
}
}
override func scrollViewDidScroll(scrollView: UIScrollView) {
if (scrollView.contentOffset.y + view.frame.size.height > scrollView.contentSize.height * 0.75) {
populatePhotos()
}
}
func populatePhotos() {
if populatingPhotos {
return
}
populatingPhotos = true
self.cellLoadingIndicator.startAnimating()
self.temporaryPictureObjects.removeAllObjects()
Alamofire.request(GWNetworking.Router.Pictures(self.currentPage)).responseJSON() { response in
if let JSON = response.result.value {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)) {
var nodeIDArray : [Int]
if (JSON .isKindOfClass(NSDictionary)) {
for node in JSON as! Dictionary<String, AnyObject> {
let nodeIDValue = node.0
var lastItem : Int = 0
self.nodeIDArray.addObject(nodeIDValue)
if let pictureElement : PictureElement = PictureElement(title: "Picture", nodeID: 0, timeStamp: 0, imageURL: "http://goldenwords.ca/sites/all/themes/custom/gw/logo.png", author: "Staff", issueNumber: "Issue # error", volumeNumber: "Volume # error") {
pictureElement.title = node.1["title"] as! String
pictureElement.nodeID = Int(nodeIDValue)!
let timeStampString = node.1["revision_timestamp"] as! String
pictureElement.timeStamp = Int(timeStampString)!
if let imageURL = node.1["image_url"] as? String {
pictureElement.imageURL = imageURL
}
if let author = node.1["author"] as? String {
pictureElement.author = author
}
if let issueNumber = node.1["issue_int"] as? String {
pictureElement.issueNumber = issueNumber
}
if let volumeNumber = node.1["volume_int"] as? String {
pictureElement.volumeNumber = volumeNumber
}
if self.pictureObjects.containsObject(pictureElement) {
// do not add the pictureElement to the set of pictures
} else {
lastItem = self.temporaryPictureObjects.count // Using a temporary set to not handle the dataSource set directly (safer).
self.temporaryPictureObjects.addObject(pictureElement)
}
let indexPaths = (lastItem..<self.temporaryPictureObjects.count).map { NSIndexPath(forItem: $0, inSection: 0) }
}
}
let timeStampSortDescriptor = NSSortDescriptor(key: "timeStamp", ascending: false)
self.temporaryPictureObjects.sortUsingDescriptors([timeStampSortDescriptor])
}
dispatch_async(dispatch_get_main_queue()) {
for object in self.temporaryPictureObjects {
self.pictureObjects.addObject(object)
}
self.temporaryPictureObjects.removeAllObjects()
self.collectionView!.reloadData()
self.cellLoadingIndicator.stopAnimating()
self.goldenWordsRefreshControl.endRefreshing()
self.currentPage++
self.populatingPhotos = false
}
}
}
}
}
func handleRefresh() {
goldenWordsRefreshControl.beginRefreshing()
self.pictureObjects.removeAllObjects()
self.temporaryPictureObjects.removeAllObjects()
self.collectionView!.reloadData()
self.currentPage = 0
self.picturesCollectionView.bringSubviewToFront(cellLoadingIndicator)
self.populatingPhotos = false
populatePhotos()
}
}
Simply reload your collectionView after the data is formatted.
picturesCollectionView.reloadData()
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView!.registerClass(PhotoBrowserCollectionViewCell.self, forCellWithReuseIdentifier: PhotoBrowserCellIdentifier)
self.revealViewController().rearViewRevealWidth = 280
collectionView!.delegate = self
collectionView!.dataSource = self
customRefreshControl = UIRefreshControl()
customRefreshControl.backgroundColor = goldenWordsYellow
customRefreshControl.tintColor = UIColor.whiteColor()
self.picturesCollectionView!.addSubview(customRefreshControl)
navigationController?.setNavigationBarHidden(false, animated: true)
navigationItem.title = "Pictures"
setupView()
populatePhotos()
self.dateFormatter.dateFormat = "dd/MM/yy"
picturesCollectionView.reloadData()
}

UIView inside UIView with TextField and Button not working

Good afternoon,
I'm trying to show a UIView when (in my case) there isn't any result to show in a tableView filled with products. When I detect 0 products, I show a UIView which contains a Label, a TextField and a Button, but I can't interact with my TextField and neither with the Button.
It's my first time using this technique to show a UIView when something went wrong with the tableView so I would like to know what's wrong in my code and what I'm missing because it's really weird.
Here is my code (when I print "Product not found" is where I show the UIView):
import UIKit
import Social
class ProductoCamViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var productoImageView:UIImageView!
#IBOutlet var tableView:UITableView!
#IBOutlet weak var noEncontrado:UIView!
var productoImage:String!
var ean:String!
var producto:Producto!
var productos = [Producto]()
#IBOutlet weak var toolBar: UIToolbar!
#IBOutlet weak var cargando: UIActivityIndicatorView!
override func viewDidLoad() {
toolBar.hidden = true
noEncontrado.hidden = true
cargando.hidden = false
super.viewDidLoad()
// Set table view background color
self.tableView.backgroundColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.2)
// Remove extra separator
self.tableView.tableFooterView = UIView(frame: CGRectZero)
// Change separator color
self.tableView.separatorColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.8)
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 88.0
requestPost()
cargando.hidden = true
tableView.reloadData()
}
override func viewDidAppear(animated: Bool) {
tableView.reloadData()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.hidesBarsOnSwipe = false
self.navigationController?.setNavigationBarHidden(false, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func requestPost () {
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.mywebsite.com/product.php")!)
request.HTTPMethod = "POST"
let postString = "ean="+ean
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil {
print("error=\(error)")
return
}
// JSON RESULTADO ENTERO
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)!
if (responseString == "Product not found")
{
self.noEncontrado.hidden = false
self.tableView.reloadData()
return
}
else
{
self.productos = self.parseJsonData(data!)
self.toolBar.hidden = false
// Reload table view
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
}
}
task.resume()
}
func parseJsonData(data: NSData) -> [Producto] {
var productos = [Producto]()
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
noEncontrado.hidden = true
// Parse JSON data
let jsonProductos = jsonResult?["lista_productos"] as! [AnyObject]
for jsonProducto in jsonProductos {
let producto = Producto()
producto.imagen = jsonProducto["imagen"] as! String
producto.nombre = jsonProducto["nombre"] as! String
producto.descripcion = jsonProducto["descripcion"] as! String
producto.modo_de_empleo = jsonProducto["modo_de_empleo"] as! String
producto.marca = jsonProducto["marca"] as! String
producto.linea = jsonProducto["linea"] as! String
producto.distribuidor = jsonProducto["distribuidor"] as! String
producto.tamano = jsonProducto["tamano"] as! String
producto.precio = jsonProducto["precio"] as! String
producto.codigo_nacional = jsonProducto["codigo_nacional"] as! String
productos.append(producto)
}
}
catch let parseError {
print(parseError)
}
return productos
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// Return the number of sections.
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// Return the number of rows in the section.
return productos.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
title = productos[indexPath.row].nombre
let cell = tableView.dequeueReusableCellWithIdentifier("CellDetail", forIndexPath: indexPath) as! ProductoTableViewCell
cell.selectionStyle = .None
if let url = NSURL(string: productos[indexPath.row].imagen) {
if let data = NSData(contentsOfURL: url) {
self.productoImageView.image = UIImage(data: data)
}
}
cell.nombre.text = productos[indexPath.row].nombre
cell.descripcion.text = productos[indexPath.row].descripcion
cell.modo_de_empleo.text = productos[indexPath.row].modo_de_empleo
cell.marca.text = productos[indexPath.row].marca
cell.linea.text = productos[indexPath.row].linea
cell.distribuidor.text = productos[indexPath.row].distribuidor
cell.tamano.text = productos[indexPath.row].tamano
cell.precio.text = productos[indexPath.row].precio
cell.codigo_nacional.text = productos[indexPath.row].codigo_nacional
cell.layoutIfNeeded()
return cell
}
}
Thanks in advance.
At first, please try to provide english code :) but anyways. I think the view what should appear is nonEncontrado.
There could be some issues but i need to see the storyboard.
The view has userInteraction not enabled. Its a property and can also be activated in the storyboard
The view is overlayed by something else. Maybe the empty tableView.
As an suggestion you could provide this fields in the tableView and just load another DataSource. Than you dont need to fight with extra views. If you provide screens from the Storyboard i could help a bit more.
Good Luck :)

Swift crashes after TableViewCell pressed

My app keeps crashing when I select the TableViewCell but it does not give me an error message. Hope some on can help. Below is the TableView Controller and the View Controller code. I have added the date into the cordite model and think it has something to do with that.
import UIKit
import CoreData
class DiveLogTableViewController: UITableViewController {
var myDivelog : Array<AnyObject> = []
override func viewDidLoad() {
super.viewDidLoad()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
override func viewDidAppear(animated: Bool) {
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
let freq = NSFetchRequest(entityName: "Divelog")
myDivelog = context.executeFetchRequest(freq, error: nil)!
tableView.reloadData()
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "update" {
var selectedItem: NSManagedObject = myDivelog[self.tableView.indexPathForSelectedRow()!.row] as! NSManagedObject
let ADLVC: AddDiveLogViewController = segue.destinationViewController as! AddDiveLogViewController
ADLVC.divenumber = selectedItem.valueForKey("divenumber") as! String
ADLVC.ddate = selectedItem.valueForKey("ddate") as! NSDate
ADLVC.divelocation = selectedItem.valueForKey("divelocation") as! String
ADLVC.existingItem = selectedItem
}
}
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 Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return myDivelog.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let CellID: NSString = "Cell"
var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(CellID as String) as! UITableViewCell
if let ip = indexPath as NSIndexPath? {
var data: NSManagedObject = myDivelog[ip.row] as! NSManagedObject
var ddate = data.valueForKey("ddate") as! NSDate
var diveloc = data.valueForKey("divelocation") as! String
var diveno = data.valueForKey("divenumber") as! String
cell.textLabel!.text = "#\(diveno)#\(diveloc)"
cell.detailTextLabel!.text = "\(ddate),location: \(diveloc)"
}
// Configure the cell...
return cell
}
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the specified item to be editable.
return true
}
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
if editingStyle == UITableViewCellEditingStyle.Delete {
if let tv = tableView as UITableView? {
context.deleteObject(myDivelog[indexPath.row] as! NSManagedObject)
myDivelog.removeAtIndex(indexPath.row)
tv.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Fade)
}
var error: NSError? = nil
if !context.save(&error) {
abort()
}
}
}
}
import UIKit
import CoreData
class AddDiveLogViewController: UIViewController {
#IBOutlet weak var textFieldDiveNumber: UITextField!
#IBOutlet weak var textFieldDiveLocation: UITextField!
#IBOutlet weak var textFieldDDate: UITextField!
var divenumber: String = ""
var divelocation: String = ""
var ddate = NSDate()
var datePickerView: UIDatePicker!
var existingItem: NSManagedObject!
override func viewDidLoad() {
super.viewDidLoad()
if (existingItem != nil) {
textFieldDiveNumber.text = divenumber
textFieldDiveLocation.text = divelocation
textFieldDDate.text = ddate.stringValue
}
// Do any additional setup after loading the view.
datePickerView = UIDatePicker()
datePickerView.datePickerMode = UIDatePickerMode.Date
var toolbar = UIToolbar(frame: CGRectMake(0, 0, datePickerView.frame.width, 44))
let OKButton = UIBarButtonItem(title: "OK", style: .Plain, target: self, action: "OKButtonTapped:")
toolbar.setItems([OKButton], animated: true)
self.textFieldDDate.inputView = datePickerView
self.textFieldDDate.inputAccessoryView = toolbar
}
#IBAction func saveTapped(sender: AnyObject) {
let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let contxt: NSManagedObjectContext = appDel.managedObjectContext!
let en = NSEntityDescription.entityForName("Divelog", inManagedObjectContext: contxt)
if (existingItem != nil) {
existingItem.setValue(textFieldDiveNumber.text, forKey: "divenumber")
existingItem.setValue(textFieldDiveLocation.text, forKey: "divelocation")
existingItem.setValue(textFieldDDate.text.dateValue!, forKey: "ddate")
} else {
var newItem = Divelog(entity: en!, insertIntoManagedObjectContext: contxt)
newItem.divenumber = textFieldDiveNumber.text
newItem.divelocation = textFieldDiveLocation.text
newItem.ddate = textFieldDDate.text.dateValue!
}
contxt.save(nil)
self.navigationController?.popToRootViewControllerAnimated(true)
}
#IBAction func cancelTapped(sender: AnyObject) {
self.navigationController?.popToRootViewControllerAnimated(true)
}
func OKButtonTapped(sender: UIBarButtonItem) {
self.textFieldDDate.endEditing(true)
self.textFieldDDate.text = datePickerView.date.stringValue
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

iOS 8 Swift: editing NSManagedObject with segue: error when declaring types

So I'm having some trouble wrapping my head around how to edit/update objects in Core Data.
What I'm trying to do is in my DetailViewController have two segues that push to my AddTableViewController.
DetailViewController:
import UIKit
import Social
import CoreData
class DetailViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var backpackerSpotImageView:UIImageView!
#IBOutlet var tableView:UITableView!
var backpackerSpot:BackpackerSpot?
var managedContext: NSManagedObjectContext!
var backpackerSpots:[BackpackerSpot] = []
var fetchResultController:NSFetchedResultsController!
override func viewDidLoad() {
super.viewDidLoad()
// customizing background of tableview
self.tableView.backgroundColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.2)
// remove extra separators
self.tableView.tableFooterView = UIView(frame: CGRectZero)
// change the color of the separator
self.tableView.separatorColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.8)
// self-sizing cells
tableView.estimatedRowHeight = 36.0
tableView.rowHeight = UITableViewAutomaticDimension
// Do any additional setup after loading the view.
if let spotImage = backpackerSpot?.spotImage
{
self.backpackerSpotImageView.image = UIImage(data:spotImage)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! DetailTableViewCell
// make cell transparent so background color can be seen
cell.backgroundColor = UIColor.clearColor()
cell.mapButton.hidden = true
switch indexPath.row {
case 0:
cell.fieldLabel.text = "Name"
cell.valueLabel.text = backpackerSpot?.spotName
case 1:
cell.fieldLabel.text = "Location"
cell.valueLabel.text = backpackerSpot?.spotLocation
cell.mapButton.hidden = false
case 2:
cell.fieldLabel.text = "Notes"
cell.valueLabel.text = backpackerSpot?.spotNote
default:
cell.fieldLabel.text = ""
cell.valueLabel.text = ""
}
return cell
}
// func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// return true
// }
//
// func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
// if(editingStyle == .Delete) {
// // Find the BackPacker Spot object the user is trying to delete
// let backpackerSpotToDelete = backpackerSpots[indexPath.row]
//
// // Delete it from the managedObjectContext
// managedContext?.deleteObject(backpackerSpotToDelete)
//
// reloadInputViews()
//
//
// }
// }
#IBAction func shareSheet(sender:UIBarButtonItem) {
let firstActivityItem = backpackerSpot!.spotName
let secondActivityItem = backpackerSpot!.spotLocation
let activityViewController : UIActivityViewController = UIActivityViewController(
activityItems: [firstActivityItem, secondActivityItem], applicationActivities: nil)
activityViewController.excludedActivityTypes = [
UIActivityTypePostToVimeo,
UIActivityTypePostToTencentWeibo,
UIActivityTypePostToFlickr,
UIActivityTypePostToWeibo,
UIActivityTypeSaveToCameraRoll,
UIActivityTypePrint,
UIActivityTypeAssignToContact,
UIActivityTypeAddToReadingList
]
self.presentViewController(activityViewController, animated: true, completion: nil)
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showMap" {
let destinationController = segue.destinationViewController as! MapViewController
destinationController.backpackerSpot = backpackerSpot
} else if segue.identifier == "editSpot"{
var selectedItem: NSManagedObject = backpackerSpot!
let destinationController = segue.destinationViewController as! AddTableViewController
destinationController.existingName = selectedItem.valueForKey("spotName") as! String
destinationController.existingLocation = selectedItem.valueForKey("spotLocation") as! String
destinationController.existingNotes = selectedItem.valueForKey("spotNote") as! String
destinationController.existingImage = selectedItem.valueForKey("spotImage") as! NSData
destinationController.existingSpot = selectedItem
destinationController.backpackerSpot = backpackerSpot
}
}
}
AddTableViewController:
import UIKit
import CoreData
class AddTableViewController: UITableViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var nameTextField:UITextField!
#IBOutlet weak var locationTextField:UITextField!
#IBOutlet weak var imageView:UIImageView!
#IBOutlet weak var notesView:UITextView!
var existingName:String = ""
var existingLocation:String = ""
var existingNotes:String = ""
var existingImage:NSData!
var existingSpot: NSManagedObject!
var coreDataStack = (UIApplication.sharedApplication().delegate as! AppDelegate).coreDataStack
var backpackerSpot:BackpackerSpot!
var managedContext: NSManagedObjectContext!
override func viewDidLoad() {
super.viewDidLoad()
managedContext = coreDataStack.context
if (existingSpot != nil) {
nameTextField.text = existingName
locationTextField.text = existingLocation
imageView.image = existingImage
notesView.text = existingNotes
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// TODO Give user the choice of the Photo Library or the Camera
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.row == 0 {
if UIImagePickerController.isSourceTypeAvailable(.Camera) {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.delegate = self
imagePicker.sourceType = .Camera
self.presentViewController(imagePicker, animated: true, completion: nil)
}
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
// FIXME image is being displayed in landscape if it is taken in portrait mode by default
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
imageView.image = image
imageView.contentMode = UIViewContentMode.ScaleAspectFill
imageView.clipsToBounds = true
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func save() {
//validation
var errorField = ""
// TODO have placeholder text in the NOTES field match up with the placholder text in the NAME and LOCATION fields.
if nameTextField.text == "" {
errorField = "name"
} else if locationTextField.text == "" {
errorField = "location"
} else if notesView.text == "" {
errorField = "notes"
}
if errorField != "" {
let alertController = UIAlertController(title: "Error", message: "You must fill in \(errorField).", preferredStyle: .Alert)
let doneAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alertController.addAction(doneAction)
self.presentViewController(alertController, animated: true, completion: nil)
return
}
// If all fields are correctly filled in, extract the field value
// Create Restaurant Object and save to data store
// if let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).coreDataStack.context {
let entityBackpackerSpot = NSEntityDescription.entityForName("BackpackerSpot", inManagedObjectContext: coreDataStack.context)
backpackerSpot = BackpackerSpot( entity: entityBackpackerSpot!, insertIntoManagedObjectContext: managedContext )
backpackerSpot?.spotName = nameTextField.text
backpackerSpot?.spotLocation = locationTextField.text
backpackerSpot?.spotImage = UIImagePNGRepresentation(imageView.image)
backpackerSpot?.spotNote = notesView.text
var error: NSError?
if !managedContext.save(&error) {
println("insert error: \(error!.localizedDescription)")
return
}
// Execute the unwind segue and go back to the home screen
performSegueWithIdentifier("unwindToHomeScreen", sender: self)
}
}
I know that I do not yet have the necessary functions to edit the data in my AddTableViewController, but the first issue I'm having is even passing the data. I'm currently getting the following error:
AddTableViewController.swift:38:31: Cannot assign a value of type 'NSData!' to a value of type 'UIImage?'
I tried casting the same variable to UIImage but that also gave me an error (which I expected).
Am I on the right track, or should I edit/update the object in a completely different way? I've been working with CoreData for a few weeks now and I'm starting to get the hang of it, but as I said before, I can't exactly wrap my head around passing the data.
Any help is appreciated. Thank you.
You need to create UIImage with your NSData first, try:
if (existingSpot != nil) {
nameTextField.text = existingName
locationTextField.text = existingLocation
imageView.image = UIImage(data: existingImage)
notesView.text = existingNotes
}

Resources