Segue to another imageview for fullsize Image - swift

I have a photoview controller that displays images in a table view. I am looking for help to segue to a fullsizeimageview imageview controller. I can't figure out how to do that.
import UIKit
import Parse
import ParseUI
class PhotosViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let arrSubCatData: NSMutableArray = [];
#IBOutlet weak var tblPhotos: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationItem.title = "Photos"
var tabBar : TabBarController = self.tabBarController as! TabBarController
println(tabBar.parkInfo)
self.tblPhotos.tableFooterView = UIView()
var query = PFQuery(className: "MultiImages")
query.whereKey("placeId", equalTo:tabBar.parkInfo?.valueForKey("objectId") as! String)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
self.arrSubCatData.addObjectsFromArray(objects!)
self.tblPhotos?.reloadData();
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("tableViewCell") as! UITableViewCell
if let file:PFFile = (self.arrSubCatData.objectAtIndex(indexPath.row).valueForKey("image") as? PFFile) {
file.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
var imgView : UIImageView = cell.contentView.viewWithTag(100) as! UIImageView
imgView.image = UIImage(data:imageData)
}
}
}
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("segueToInfo", sender: indexPath.row)
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.arrSubCatData.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
/*override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showfullsizeimage" {
if let indexPath = self.tableView.indexPathForSelectedRow() {
let detailViewController = segue.destinationViewController as! PhotoFullSizeController
detailViewController.detailItem = objects[indexPath.row]
}
}
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
My newly created fullsize image controller is like this with segue identifier "fullsizeimageview"
import UIKit
class PhotoFullSizeController: UIViewController {
#IBOutlet weak var fullImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

First of all, You should add TapGesture to the imgView.
Your cellForRowIndexPath will be now as follow :
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("tableViewCell") as! UITableViewCell
if let file:PFFile = (self.arrSubCatData.objectAtIndex(indexPath.row).valueForKey("image") as? PFFile) {
file.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
var imgView : UIImageView = cell.contentView.viewWithTag(100) as! UIImageView
//Add Tap Gesture to the imgView
imgView.userInteractionEnabled = true;
let tapRecognizer = UITapGestureRecognizer(target: self, action: Selector("imageTapped"))
imgView.addGestureRecognizer(tapRecognizer)
imgView.image = UIImage(data:imageData)
}
}
}
}
return cell
}
Now write a handler for imageTapped
//When image is tapped
func imageTapped()
{
println("image tapped")
self.performSegueWithIdentifier("fullsizeimageview", sender: self)
}
And prepareForSegue will look as follow :
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "fullsizeimageview")
{
let destVC = (segue.destinationViewController as? PhotoFullSizeController)!
let indexPath = self.tblPhotos.indexPathForSelectedRow() //IndexPath for selected table row
if let file:PFFile = (self.arrSubCatData.objectAtIndex(indexPath!.row).valueForKey("image") as? PFFile) {
destVC.imageFile = file
}
}
}
In your PhotoFullSizeController controller
class PhotoFullSizeController: UIViewController {
#IBOutlet weak var fullImageView: UIImageView!
var imageFile: PFFile!
override func viewDidLoad() {
super.viewDidLoad()
// Load image
self.imageFile.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
//Set image in imageview
fullImageView.image = UIImage(data:imageData)
}
}
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Let me know if any issue is there. Hope this will help!

Related

How to input the value from UI button in Teble View cell to the variable declared in Table View Controller?

I want to save the value of filled button(●) into the array "q.answer[indexPath.row]" about each question "q.question[indexPath.row]).
currentQuizButtonIndex is currently renewed every time when ◯ changes to ● by tapping. However, I have no idea how to save in to variable q which is declared in TableViewController.
View Controller display
Code about QuizCell.swift (TableCell which is about 5 buttons and UIlabel.)
import UIKit
import Foundation
protocol QuizCellDelegate {
func quizCellDidChangeCurrentButtonIndex(_ cell: QuizCell, index: Int)
}
class QuizCell: UITableViewCell {
var currentQuizButtonIndex: Int = 0 {
didSet {
let value = self.currentQuizButtonIndex
self.updateCurrentQuizButton(value)
if let delegate = self.delegate {
delegate.quizCellDidChangeCurrentButtonIndex(self, index: value)
}
}
}
#IBOutlet weak var questionLabel: UILabel!
#IBOutlet var answerButtons: [UIButton]!
var delegate: QuizCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
//print("ここまできてるか確認")
// Initialization code
}
#IBAction func didTapQuizButton(_ sender: UIButton) {
if let index = self.answerButtons.firstIndex(of: sender){
self.currentQuizButtonIndex = index
delegate?.quizCellDidChangeCurrentButtonIndex(self, index: index)
print(index)
}
}
private func updateCurrentQuizButton(_ currentIndex: Int){
for (index, answerButton) in self.answerButtons.enumerated(){
if index == currentIndex {
answerButton.setTitle("●", for: .normal)
} else {
answerButton.setTitle("○", for: .normal)
}
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Code about View Controller
import UIKit
class AnswerQuizViewController: UIViewController, UITableViewDelegate {
var q: QuestionSeries!
#IBOutlet weak var quizTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
quizTableView.dataSource = self
quizTableView.delegate = self
// cell xibファイルを使うときは書く必要があるやつ。
// quizTableView.register(UINib(nibName: K.Cells.QuizCellNibName, bundle: nil), forCellReuseIdentifier: K.Cells.QuizCellIdentifier)
quizTableView.register(UINib(nibName: "QuizCell", bundle: nil), forCellReuseIdentifier: "QuizCellIdentifier")
// Do any additional setup after loading the view.
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
// override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// // Get the new view controller using segue.destination.
// // Pass the selected object to the new view controller.
//// if segue.identifier == K.Segue.checkResult {
//// let resultViewController = segue.destination as! ResultViewController
//// answerQuizViewController.q =
//// print(answerQuizViewController.q)
// }
}
// MARK: - quizTableViewのアレンジ
extension AnswerQuizViewController: UITableViewDataSource, QuizCellDelegate {
func quizCellDidChangeCurrentButtonIndex(_ cell: QuizCell, index: Int) {
if let indexPath = self.quizTableView.indexPath(for: cell){
self.q.question[indexPath.row].answer = index
print(index)
}else{
print("ここきてます")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return q.question.count
//print(q.question.count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let question = q.question[indexPath.row]
let cell = quizTableView.dequeueReusableCell(withIdentifier: K.Cells.QuizCellIdentifier, for: indexPath) as! QuizCell
cell.questionLabel.text = question.text
// print(question.text)
return cell
}
}
It is also helpful if you have any idea of implementing this by alternative way.
Thanks.
How about you create a static array and store your data into that array.
when the button is tapped you can append it into that static array.
Create a new file. Just a basic "Swift file".
struct structName {
static var qArray: [String] = []
}
Then append data by:
structName.q.append()
Finally get your data trough:
structName.q[index]

Blank labels after data passing in Swift 4?

I am currently trying to pass data from my table view controller to a second view controller but my labels and image are appearing as blank in the second view controller.
This is my main event view controller:
class EventsTableViewController: PFQueryTableViewController {
override func queryForTable() -> PFQuery<PFObject> {
let query = PFQuery(className: "Events")
//query.order(byAscending: "location")
query.order(byAscending: "date")
return query
}
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Upcoming Events"
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MasterToDetail" {
let detailVC = segue.destination as! DetailViewController
detailVC.myEventCell = sender as? EventCell
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath, object: PFObject?) -> PFTableViewCell? {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! EventCell
cell.dateLabel.text = object?.object(forKey: "date") as? String
cell.locationLabel.text = object?.object(forKey: "location") as? String
cell.nameLabel.text = object?.object(forKey: "name") as? String
let imageFile = object?.object(forKey: "image") as? PFFile
cell.eventImage.image = UIImage(named: "download")
cell.eventImage.file = imageFile
cell.eventImage.loadInBackground()
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "MasterToDetail", sender: EventCell())
}
#IBAction func reloadTable(_ sender: Any) {
self.loadObjects()
}
#IBAction func onSignOutTapped(_ sender: Any) {
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
performSegue(withIdentifier: "signOutSegue", sender: nil)
} catch {
print (error)
}
}
}
and my second view controller:
class DetailViewController: UIViewController {
#IBOutlet weak var detailImageView: UIImageView!
#IBOutlet weak var detailNameLabel: UILabel!
#IBOutlet weak var detailDescriptionLabel: UILabel!
#IBOutlet weak var detailLocationLabel: UILabel!
var myEventCell: EventCell?
override func viewDidLoad() {
super.viewDidLoad()
setUI()
}
func setUI () {
detailNameLabel.text = myEventCell?.nameLabel.text
detailImageView.image = myEventCell?.eventImage.image
detailLocationLabel.text = myEventCell?.locationLabel.text
}
}
As you send an empty cell here
performSegue(withIdentifier: "MasterToDetail", sender: EventCell())
You need
let cell = tableView.cellForRow(at:indexPath)
performSegue(withIdentifier: "MasterToDetail", sender:cell)

Can't update a value with Core Data

first i come from France so sorry for my english.
Second, I'm new in developpement and i have develop a code for add data and after show them with Core Data. it works.ok
but after i want update but i have a problem i don't know why i can't update my value. There is an error : "fatal error: unexpectedly found nil while unwrapping an Optional value"
i have try many solution since 1 week, but can't find the problem. Thanks if someone can help me ! even a little help :)
this is my code (swift 2.3) :
for show in table view :
import UIKit
import CoreData
class ProduitTableViewController: UITableViewController {
#IBOutlet var table: UITableView!
var produits = [NSManagedObject]()
func refreshStories(refreshControl: UIRefreshControl) {
produits.removeAll()
fetchData()
self.table.reloadData()
refreshControl.endRefreshing()
}
override func viewDidLoad() {
super.viewDidLoad()
self.fetchData()
self.table.addSubview(self.refreshControl!)
self.refreshControl?.addTarget(self, action: #selector(ProduitTableViewController.refreshStories(_:)), forControlEvents: UIControlEvents.ValueChanged)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func fetchData() {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
//2
let fetchRequest = NSFetchRequest(entityName: "Produits")
let sort = NSSortDescriptor(key:"dateAjout", ascending:true)
fetchRequest.sortDescriptors = [sort]
//3
do {
let results = try managedContext.executeFetchRequest(fetchRequest)
produits = results as! [NSManagedObject]
} catch let error as NSError {
print("Donnees non recu \(error), \(error.userInfo)")
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return self.produits.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")
let produit = produits[indexPath.row]
cell!.textLabel!.text = produit.valueForKey("nom") as? String
/*
let id = produit.valueForKey("id") as? String
let date = produit.valueForKey("date") as? NSDate
let localNotification = UILocalNotification()
localNotification.userInfo = ["id" : id!]
localNotification.soundName = UILocalNotificationDefaultSoundName
localNotification.alertBody = "expiré"
localNotification.fireDate = date
UIApplication.sharedApplication().scheduleLocalNotification(localNotification)
UIApplication.sharedApplication().applicationIconBadgeNumber += 1
*/
return cell!
}
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let supprimer = UITableViewRowAction(style: .Normal, title: "Suppr.") { action, index in
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let moc = appDelegate.managedObjectContext
// 3
moc.deleteObject(self.produits[indexPath.row])
appDelegate.saveContext()
// 4
self.produits.removeAtIndex(indexPath.row)
tableView.reloadData()
}
supprimer.backgroundColor = UIColor.redColor()
let update = UITableViewRowAction(style: .Normal, title: "Modifier") { action, index in
}
update.backgroundColor = UIColor.blueColor()
return [supprimer]
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// the cells you would like the actions to appear needs to be editable
return true
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "showDetail" {
if let destination = segue.destinationViewController as? DetailViewController {
let row = table.indexPathForSelectedRow?.row
let produit = produits[row!]
let nom = produit.valueForKey("nom") as? String
let id = produit.valueForKey("id") as? String
let detail = produit.valueForKey("detail") as? String
let date = produit.valueForKey("date") as? NSDate
let time = date
let formatter = NSDateFormatter()
formatter.dateFormat = "dd-MM-YY HH:mm"
let formatteddate = formatter.stringFromDate(time!)
destination.dataNom = nom!
destination.dataId = id!
destination.dataDetail = detail!
destination.dataDate = formatteddate
}
}
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if table.cellForRowAtIndexPath(indexPath) != nil {
self.performSegueWithIdentifier("showDetail", sender: self)
}
}
}
for show detail of the cell :
import CoreData
import UIKit
class DetailViewController: UIViewController {
#IBOutlet var Label: UILabel!
#IBOutlet var Detail: UITextView!
#IBOutlet weak var Date: UILabel!
#IBOutlet weak var Id: UILabel!
var dataNom = ""
var dataDetail = ""
var dataDate = ""
var dataId = ""
override func viewDidLoad() {
super.viewDidLoad()
Label.text = dataNom
Detail.text = dataDetail
Date.text = dataDate
Id.text = dataId
// Do any additional setup after loading the view
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "ModifierDetail" {
if let destination = segue.destinationViewController as? ModifierViewController {
destination.modifierNom = dataNom
destination.modifierId = dataId
destination.modifierDetail = dataDetail
destination.modifierDate = dataDate
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
And the last for update/modify my detail:
import UIKit
import CoreData
class ModifierViewController: UIViewController {
#IBOutlet weak var Nom: UITextField!
#IBOutlet weak var Detail: UITextView!
#IBOutlet weak var Date: UITextField!
var Produits: NSManagedObject!
var managedContext: NSManagedObjectContext!
var modifierNom = ""
var modifierDetail = ""
var modifierDate = ""
var modifierId = ""
override func viewDidLoad() {
super.viewDidLoad()
Nom.text = modifierNom
Detail.text = modifierDetail
Date.text = modifierDate
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func Annuler(sender: UIBarButtonItem) {
navigationController?.popViewControllerAnimated(true)
}
#IBAction func Modifier(sender: UIButton) {
let fetchRequest = NSFetchRequest(entityName:"Produits")
fetchRequest.predicate = NSPredicate(format: "nom = %#", modifierNom)
do {
let list = try managedContext.executeFetchRequest(fetchRequest) as! [Produit]
if list.count == 0 // Check notificationId available then not save
{
let newManagedObject = NSEntityDescription.insertNewObjectForEntityForName("Produits", inManagedObjectContext: managedContext)
newManagedObject.setValue(modifierNom, forKey: "nom")
}
// success ...
} catch let error as NSError {
// failure
print("Fetch failed: \(error.localizedDescription)")
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
i have create this other file:
import Foundation
import CoreData
#objc(Produit)
class Produit: NSManagedObject {
#NSManaged var nom:String!
}
As you mentioned in the comment, this line causes the crash:
let list = try managedContext.executeFetchRequest(fetchRequest) as! [Produit]
That line is not safe, because you don't know, if casting to [Prodiut]will always be successful.
In general, you should never force-cast (as!) or force-unwrap (!) something when you don't know 1000%, that it will succeed.
To cast safely, you can use guard:
guard let list = try managedContext.executeFetchRequest(fetchRequest) as! [Produit] else {
//do some error handling here and then return
return
}
After that, you can safely use list.
It's really important to understand, what optionals are and how to handle them safely without crashes.

Difficulties in moving Page in swift

when I select UIButoon(selectMaghsad or selectMabda) go AircraftSearch to SelectedCity without difficulty and problem I choose one cell in selecteCity(tableviewController) go back to AircraftSearch and show data in label (labelcity) The problem is that Without that I want again go to tableViewController(selecteCity)
and alert :
A
Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo={NSLocalizedDescription=unsupported URL, NSUnderlyingError=0x7f867b5a4920 {Error Domain=kCFErrorDomainCFNetwork Code=-1002 "(null)"}}
why ??
Where do you think the problem is?
can you help me ??
AircraftSearch
class AircraftSearch: UIViewController ,SendbackDelegate{
#IBOutlet weak var Mabda: UIButton!
#IBOutlet weak var maghsad: UIButton!
#IBOutlet weak var labelcity: UILabel!
#IBOutlet weak var cityTectfield: UITextField!
var Airurl = NSURL()
var ScrOrDstArray = [MabdaAndMaghsad]()
var origin = [String]() // save mabda
var purpose = [String]() // save maghsad
var sendDataToTableview = [String]()
var tit = String()
override func viewDidLoad() {
super.viewDidLoad()
labelcity.text = tit
GetPassCity()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func selectMabda(sender: AnyObject) {
sendDataToTableview = origin
performSegueWithIdentifier("SelectedCellSegue", sender: sender)
}
#IBAction func selectMaghsad(sender: AnyObject) {
sendDataToTableview = purpose
print(sendDataToTableview)
performSegueWithIdentifier("SelectedCellSegue", sender: sender)
}
func originAndpurpose() {
let dataCity = ScrOrDstArray
for i in dataCity{
if i.SrcOrDst == true{
origin.append(i.Name)
}else{
purpose.append(i.Name)
}
}
}
func GetPassCity(){
let actInd : UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRectMake(0,0, 50, 50)) as UIActivityIndicatorView
actInd.center = self.view.center
actInd.hidesWhenStopped = true
actInd.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
view.addSubview(actInd)
actInd.startAnimating()
NSURLSession.sharedSession().dataTaskWithURL(Airurl){ ( data ,response ,error) in
if error != nil{
print("A")
print(error!)
}else{
do{
//readin data from Server
let posts = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! [[String:AnyObject]]
//save data
for post in posts{
var postCity:MabdaAndMaghsad?
if let Id = post["Id"] as? Int ,
let nameCity = post["Name"] as? String ,
let SrcOrDst = post["SrcOrDst"] as? Bool
{
postCity = MabdaAndMaghsad(ID: Id, Name: nameCity, SrcOrDst: SrcOrDst)
}
self.ScrOrDstArray.append(postCity!)
}
//===============
dispatch_async(dispatch_get_main_queue()){
actInd.stopAnimating()
self.originAndpurpose()
print(self.origin)
print("=======")
// print(self.purpose)
}
}catch let error as NSError{
print("B")
print(error)
}
}
}.resume()
}
func sendNameToPreviousVC(SelectCity: String) {
tit = SelectCity
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SelectedCellSegue" {
if let VC = segue.destinationViewController as? SelectedCity {
VC.toTake = sendDataToTableview
VC.delegate = self
}
}
}
}
SelectedCity view
import UIKit
protocol SendbackDelegate:class {
func sendNameToPreviousVC(City:String)
}
class SelectedCity: UITableViewController {
var toTake = [String]()
var selecteCity = String()
weak var delegate: SendbackDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(false, animated: true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return toTake.count ?? 0
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("stcell", forIndexPath: indexPath) as? mAndMCell
let nameCity = toTake[indexPath.row]
print(nameCity)
cell!.nameCityLabel.text = nameCity
return cell!
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as! mAndMCell!
selecteCity = currentCell.nameCityLabel!.text as String!
sendBackIdCity(selecteCity)
navigationController?.popViewControllerAnimated(true)
}
func sendBackIdCity(name: String){
self.delegate?.sendNameToPreviousVC(name)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "backCitySegue"{
var VCOne = segue.destinationViewController as? AircraftSearch
self.delegate = VCOne
}
}
}
pic

tableView.reloadData() causing a crash of the app

In the Swift app, I present an addition view to add an element to the CoreData database. If I call tableview.reloadData(), the app crashes on the + button on the main screen. If I omit the reload data then the add view is presented and the data is added to the CoreData file.
the main view, from configureCell down:
func configureCell(cell: TransectTableViewCell, indexPath:NSIndexPath) {
let transectEntry = fetchedResultController.objectAtIndexPath(indexPath) as! Transects
cell.transectNameLabel.text = transectEntry.transectName
cell.transectNameLabel.textColor = UIColor.blackColor()
cell.transectNameLabel.shadowColor = UIColor.whiteColor()
cell.transectNameLabel.shadowOffset = CGSizeMake(1, 1)
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let countEntry = fetchedResultController.objectAtIndexPath(indexPath) as! Transects
coreDataStack.context.deleteObject(countEntry)
coreDataStack.saveContext()
}
}
func tableView(tableView: UITableView,
heightForRowAtIndexPath indexPath: NSIndexPath)
-> CGFloat {
return 50;
}
func didFinishViewController(viewController: AddTransectViewController, didSave: Bool) {
if didSave {
var error: NSError? = nil
let context = viewController.context
self.coreDataStack.saveContext()
}
dismissViewControllerAnimated(true, completion: {})
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "addTransectSegue" {
let newTransectViewController = segue.destinationViewController as! AddTransectViewController
let transectEntryEntity = NSEntityDescription.entityForName("Transects", inManagedObjectContext: coreDataStack.context)
let newTransectEntry = Transects(entity: transectEntryEntity!, insertIntoManagedObjectContext: coreDataStack.context)
newTransectViewController.transectNewEntry = newTransectEntry
newTransectViewController.context = newTransectEntry.managedObjectContext
newTransectViewController.delegate = self
}
if segue.identifier == "transectTasksSegue" {
let indexPath = tableView.indexPathForSelectedRow()!
let transectSelected = fetchedResultController.objectAtIndexPath(indexPath) as! Transects
let tasksViewController = segue.destinationViewController as! TransectTasksViewController
tasksViewController.coreDataStack = coreDataStack
tasksViewController.selectedTransect = transectSelected
}
}
func controllerDidChangeContent(controller:
NSFetchedResultsController) {
tableView.reloadData()
}
The addition view is:
import UIKit
import CoreData
import Foundation
protocol TransectDelegate {
func didFinishViewController(ViewController:AddTransectViewController, didSave:Bool)
}
class AddTransectViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var transectNameTextField: UITextField!
#IBOutlet weak var latitudeTextField: UITextField!
#IBOutlet weak var longitudeTextField: UITextField!
#IBOutlet weak var altitudeTextField: UITextField!
var transectNewEntry: Transects!
var context: NSManagedObjectContext!
var delegate:TransectDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func updateTransectEntry() {
if let entry = transectNewEntry {
entry.transectName = transectNameTextField.text
entry.latitude = latitudeTextField.text
entry.longitude = longitudeTextField.text
entry.altitude = altitudeTextField.text
}
}
#IBAction func cancelButtonWasTapped(sender: AnyObject) {
delegate?.didFinishViewController(self, didSave: false)
}
#IBAction func saveButtonWasTapped(sender: AnyObject) {
updateTransectEntry()
delegate?.didFinishViewController(self, didSave: true)
}
}
I am missing something, but cannot see what. Ideas would be welcome.
The app hangs up on cell.transectNameLabel.text = transectEntry.transectName
with: Thread 1:EXC_BAD_ACCESS (code=1, address=0x0)
My real confusion is that this works perfectly:
import UIKit
import CoreData
class PlantSpeciesViewController: UIViewController, NSFetchedResultsControllerDelegate, PlantSpeciesDelegate, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var tableView:UITableView!
var coreDataStack: CoreDataStack!
lazy var fetchedResultController:
NSFetchedResultsController = self.plantSpeciesFetchedResultsController()
var plantSpecies: PlantSpecies!
var selectedFamily: PlantFamily!
var context: NSManagedObjectContext!
var plantFamilyName: String!
override func viewDidLoad() {
super.viewDidLoad()
tableView.backgroundColor = UIColor.clearColor()
view.backgroundColor = UIColor(patternImage: UIImage (named: "Monitor backdrop.png")!)
self.title = plantFamilyName
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func plantSpeciesFetchedResultsController()
->NSFetchedResultsController {
fetchedResultController =
NSFetchedResultsController(
fetchRequest: plantSpeciesFetchRequest(),
managedObjectContext: coreDataStack.context,
sectionNameKeyPath: nil,
cacheName: nil)
fetchedResultController.delegate = self
var error: NSError? = nil
if (!fetchedResultController.performFetch(&error)){
println("Error: \(error?.localizedDescription)")
abort()
}
return fetchedResultController
}
func plantSpeciesFetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "PlantSpecies")
fetchRequest.fetchBatchSize = 20
let predicate = NSPredicate(format: "familyName == %#", selectedFamily)
fetchRequest.predicate = predicate
let sortDescriptor = NSSortDescriptor(key: "plantSpecies", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
//var error: NSError?
return fetchRequest
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return fetchedResultController.sections!.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return fetchedResultController.sections![section].numberOfObjects
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("plantSpeciesCell", forIndexPath: indexPath) as! PlantSpeciesTableViewCell
cell.backgroundColor = UIColor.clearColor()
configureCell(cell, indexPath: indexPath)
return cell
}
func configureCell(cell: PlantSpeciesTableViewCell, indexPath:NSIndexPath) {
let plantEntry = fetchedResultController.objectAtIndexPath(indexPath) as! PlantSpecies
cell.speciesNameLabel.text = plantEntry.plantSpecies
cell.speciesNameLabel.textColor = UIColor.blackColor()
cell.speciesNameLabel.shadowColor = UIColor.whiteColor()
cell.speciesNameLabel.shadowOffset = CGSizeMake(1, 1)
cell.speciesImageView.image = UIImage (data: plantEntry.plantImage)
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let countEntry = fetchedResultController.objectAtIndexPath(indexPath) as! PlantFamily
coreDataStack.context.deleteObject(countEntry)
coreDataStack.saveContext()
}
}
func tableView(tableView: UITableView,
heightForRowAtIndexPath indexPath: NSIndexPath)
-> CGFloat {
return 90;
}
func didFinishViewController(viewController: AddPlantSpeciesViewController, didSave: Bool) {
if didSave {
var error: NSError? = nil
let context = viewController.context
self.coreDataStack.saveContext()
}
dismissViewControllerAnimated(true, completion: {})
}
// MARK: - Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "addSpeciesSegue" {
let newPlantViewController = segue.destinationViewController as! AddPlantSpeciesViewController
let plantEntryEntity = NSEntityDescription.entityForName("PlantSpecies", inManagedObjectContext: coreDataStack.context)
let newSpeciesEntry = PlantSpecies(entity: plantEntryEntity!, insertIntoManagedObjectContext: coreDataStack.context)
newPlantViewController.selectedFamily = selectedFamily
newPlantViewController.plantNameEntry = newSpeciesEntry
newPlantViewController.context = newSpeciesEntry.managedObjectContext
newPlantViewController.delegate = self
}
}
func controllerDidChangeContent(controller:
NSFetchedResultsController) {
tableView.reloadData()
}
}
coupled with:
import UIKit
import CoreData
import Foundation
protocol PlantSpeciesDelegate {
func didFinishViewController(ViewController:AddPlantSpeciesViewController, didSave:Bool)
}
class AddPlantSpeciesViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var plantNameTextField: UITextField!
#IBOutlet weak var plantImageView: UIImageView!
#IBOutlet weak var imageSwitch: UISwitch!
#IBOutlet weak var imageFromFileButton: UIButton!
#IBOutlet weak var imageFromCameraButton: UIButton!
let imagePicker = UIImagePickerController()
var plantNameEntry: PlantSpecies!
var selectedFamily: PlantFamily!
var passedPlantFamily: String!
var newPlantName: String!
var newImageData: NSData!
var context: NSManagedObjectContext!
var delegate:PlantSpeciesDelegate?
override func viewDidLoad() {
super.viewDidLoad()
plantImageView.image = UIImage(named: "placeholder image.jpg")
imagePicker.delegate = self
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func imageSourceSwitch(sender: AnyObject) {
if imageSwitch.on == true
{
self.imageFromFileButton.enabled = true
self.imageFromCameraButton.enabled = false
}
else
{
self.imageFromCameraButton.enabled = true
self.imageFromFileButton.enabled = false
}
}
#IBAction func imageFromFile(sender: AnyObject) {
imagePicker.sourceType = .PhotoLibrary
presentViewController(imagePicker, animated: true, completion: nil)
}
#IBAction func imageFromCamera(sender: AnyObject) {
imagePicker.sourceType = .Camera
presentViewController(imagePicker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
self.plantImageView.image = image
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func getPlantName() {
newPlantName = plantNameTextField.text
plantNameTextField.resignFirstResponder()
}
func updateSpeciesEntry() {
if let entry = plantNameEntry {
entry.plantSpecies = newPlantName
entry.plantImage = UIImageJPEGRepresentation(plantImageView.image, 1.0)
entry.familyName = selectedFamily
}
}
#IBAction func cancelButtonWasTapped(sender: AnyObject) {
delegate?.didFinishViewController(self, didSave: false)
}
#IBAction func saveButtonWasTapped(sender: AnyObject) {
updateSpeciesEntry()
delegate?.didFinishViewController(self, didSave: true)
}
}
So, what is the difference?
This happen to me too, fixed it with:
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
instead of just tableView.reloadData()
, cause it seems that it was being called from wrong thread.
The reason for the crash is most likely that the table cannot load the data, for example a value does not exist and is being force unwrapped. The crash only happens, therefore, when you try to collect the data. Check through all the values to be sure.
I'd like to expand on GJZ answer & what brought me here. I have UITableViewCells that have a textfield. I attempted to get values the user entered from the field.
let companyNameCell: TextEntryCell = self.tableView.cellForRow(at: IndexPath(row: 0, section: 0)) as! TextEntryCell
what I realized is that when I dynamically hide and showed rows by changing the cell heights using the tableview.reloadrows method, the app would crash if it attempted to read a cell the user could not see on their screen. that is because the cells I think were deallocated.