My app is crashing because of a memory issue (Too much memory used). It happens when i open enough of the objects from the TableView. I has searched the internet for the problem, and i can see it might be because the memory never is released. But how do i release it?
Here is my code.
TableExerciseViewController
class TableExercisesViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var choosenCellIndex = 0
var filteredExercises = [Exercise]()
let searchController = UISearchController(searchResultsController: nil)
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.searchBar.placeholder = "Look up an exercise..."
definesPresentationContext = true
tableView.tableHeaderView = searchController.searchBar
}
override func viewDidAppear(animated: Bool) {
if let row = tableView.indexPathForSelectedRow {
self.tableView.deselectRowAtIndexPath(row, animated: false)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func filterContentForSearchText(searchText: String, scope: String = "All") {
filteredExercises = ExerciseManager.sharedInstance.getExercises().filter {
exercise in return exercise.name.lowercaseString.containsString(searchText.lowercaseString)
}
tableView.reloadData()
}
//Returns the size of the arraylist
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if searchController.active && searchController.searchBar.text != "" {
return filteredExercises.count
}
return ExerciseManager.sharedInstance.getExercises().count
}
//Returns the selected Cell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Exercise Cell", forIndexPath: indexPath) as! ExerciseCustomCell
let exercise: Exercise
if searchController.active && searchController.searchBar.text != "" {
exercise = filteredExercises[indexPath.row]
} else {
exercise = ExerciseManager.sharedInstance.getExercises()[indexPath.row]
}
cell.imgExercise?.image = exercise.exerciseImage1
cell.lblExerciseName?.text = exercise.name
cell.lblExerciseMuscleGroup?.text = exercise.muscle
cell.lblExerciseTools?.text = "Equipment: \(exercise.tool)"
return cell
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
//Sends the data through the selected identifier
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
choosenCellIndex = indexPath.row
// Start segue with index of cell clicked
self.performSegueWithIdentifier("Show Exercise", sender: self)
}
//Prepares the data for the segue and the next viewcontroller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// get a reference to the second view controller
let exerciseViewController = segue.destinationViewController as! ExerciseViewController
// set a variable in the second view controller with the data to pass
if searchController.active && searchController.searchBar.text != "" {
exerciseViewController.exercise = filteredExercises[choosenCellIndex]
} else {
exerciseViewController.exercise = ExerciseManager.sharedInstance.getExercises()[choosenCellIndex]
}
}
deinit {
debugPrint("TableExerciseView deinitialized...")
}
}
extension TableExercisesViewController: UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
filterContentForSearchText(searchController.searchBar.text!)
}
ExerciseViewController
class ExerciseViewController: UIViewController {
weak var exercise: Exercise?
var receivedCellIndex = 0
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var lblExerciseName: UILabel!
#IBOutlet weak var lblExerciseMuscleGroup: UILabel!
#IBOutlet weak var lblStartDescription: UILabel!
#IBOutlet weak var lblLastDescription: UILabel!
#IBOutlet weak var imgExerciseAnimation: UIImageView!
#IBOutlet weak var imgExerciseStartPosition: UIImageView!
#IBOutlet weak var imgExerciseLastPosition: UIImageView!
var timer = NSTimer()
var counter = 1
override func viewDidLoad() {
super.viewDidLoad()
//Sets the color of the back button in navigation bar
self.navigationController!.navigationBar.tintColor = UIColor.whiteColor();
//Sets the labels
lblExerciseName.text = exercise?.name
lblExerciseMuscleGroup.text = exercise!.muscle
lblStartDescription.text = "1. \(exercise!.startDescription)"
lblLastDescription.text = "2. \(exercise!.lastDescription)"
//Sets the antimation and the images
imgExerciseAnimation.image = exercise?.exerciseImage1
imgExerciseStartPosition.image = exercise?.exerciseImage1
imgExerciseLastPosition.image = exercise?.exerciseImage2
//Timer
self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(ExerciseViewController.demonstrateExercise), userInfo: nil, repeats: true)
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.timer.invalidate()
}
func demonstrateExercise() {
if counter == 1 {
imgExerciseAnimation.image = exercise?.exerciseImage2
counter += 1
} else {
counter = 1
imgExerciseAnimation.image = exercise?.exerciseImage1
}
}
}
I'm guessing that what's taking up the memory are the exercise images in your ExerciseViewController. Since Swift uses ARC to manage memory, you'll want to remove references to those images (and exercice for that matter) so that the system can release them from memory.
override func viewDidDisappear(animated: Bool) {
lblExerciseName.text = nil
lblExerciseMuscleGroup.text = nil
lblStartDescription.text = nil
lblLastDescription.text = nil
imgExerciseAnimation.image = nil
imgExerciseStartPosition.image = nil
imgExerciseLastPosition.image = nil
}
Since your exercice variable is weak, and nothing is referencing to it, the system will now free it from memory instead of having multiple copies of exercices build up every time the user visits a new ExerciseViewController.
Override deinit function - and check if its called when you exit the Exercise view. If not - i would destroy the timer in viewWillDisappear or Did functions.
Related
I want to pass the data from one view controller to another view controller when the user clicked the button . I am using button with delegate to pass the table view cell values into different view controller view . In second view controller I have two labels and one image to display the fields but the problem is when I clicked the button it is empty.
Here is the cell code .
import UIKit
protocol CellSubclassDelegate: AnyObject {
func buttonTapped(cell: MovieViewCell)
}
class MovieViewCell: UITableViewCell {
weak var delegate:CellSubclassDelegate?
static let identifier = "MovieViewCell"
#IBOutlet weak var movieImage: UIImageView!
#IBOutlet weak var movieTitle: UILabel!
#IBOutlet weak var movieOverview: UILabel!
#IBOutlet weak var someButton: UIButton!
#IBAction func someButtonTapped(_ sender: UIButton) {
self.delegate?.buttonTapped(cell: self)
}
override func prepareForReuse() {
super.prepareForReuse()
self.delegate = nil
}
func configureCell(title: String?, overview: String?, data: Data?) {
movieTitle.text = title
movieOverview.text = overview
if let imageData = data{
movieImage.image = UIImage(data: imageData)
// movieImage.image = nil
}
}
}
Here is the first view controller code .
import UIKit
class MovieViewController: UIViewController, UISearchBarDelegate {
#IBOutlet weak var userName: UILabel!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var searchBar: UISearchBar!
private var presenter: MoviePresenter!
var finalname = ""
var movieTitle = ""
var movieOverview = ""
var movieImage : UIImage?
override func viewDidLoad() {
super.viewDidLoad()
userName.text = "Hello: " + finalname
setUpUI()
presenter = MoviePresenter(view: self)
searchBarText()
}
private func setUpUI() {
tableView.dataSource = self
tableView.delegate = self
}
private func searchBarText() {
searchBar.delegate = self
}
#IBAction func selectSegment(_ sender: UISegmentedControl) {
if sender.selectedSegmentIndex == 0{
setUpUI()
presenter = MoviePresenter(view: self)
presenter.getMovies()
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if searchText == ""{
presenter.getMovies()
}
else {
presenter.movies = presenter.movies.filter({ movies in
let originalTitle = movies.originalTitle.lowercased().range(of: searchText.lowercased())
let overview = movies.overview.lowercased().range(of: searchText.lowercased())
let posterPath = movies.posterPath.lowercased().range(of: searchText.lowercased())
return (originalTitle != nil) == true || (overview != nil) == true || (posterPath != nil) == true}
)
}
tableView.reloadData()
}
}
extension MovieViewController: MovieViewProtocol {
func resfreshTableView() {
tableView.reloadData()
}
func displayError(_ message: String) {
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
let doneButton = UIAlertAction(title: "Done", style: .default, handler: nil)
alert.addAction(doneButton)
present(alert, animated: true, completion: nil)
}
}
extension MovieViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
presenter.rows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MovieViewCell.identifier, for: indexPath) as! MovieViewCell
let row = indexPath.row
let title = presenter.getTitle(by: row)
let overview = presenter.getOverview(by: row)
let data = presenter.getImageData(by: row)
cell.delegate = self
cell.configureCell(title: title, overview: overview, data: data)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let dc = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as! MovieDeatilsViewController
let row = indexPath.row
dc.titlemovie = presenter.getTitle(by: row) ?? ""
dc.overview = presenter.getOverview(by: row) ?? ""
dc.imagemovie = UIImage(data: presenter.getImageData(by: row)!)
self.navigationController?.pushViewController(dc, animated: true)
}
}
extension MovieViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
}
extension MovieViewController : CellSubclassDelegate{
func buttonTapped(cell: MovieViewCell) {
guard (self.tableView.indexPath(for: cell) != nil) else {return}
let customViewController = storyboard?.instantiateViewController(withIdentifier: "MovieDeatilsViewController") as? MovieDeatilsViewController
customViewController?.titlemovie = movieTitle
customViewController?.imagemovie = movieImage
customViewController?.overview = movieOverview
self.navigationController?.pushViewController(customViewController!, animated: true)
}
}
Here is the details view controller code .
class MovieDeatilsViewController: UIViewController {
#IBOutlet weak var movieImage: UIImageView!
#IBOutlet weak var movieTitle: UILabel!
#IBOutlet weak var movieOverview: UILabel!
var titlemovie = ""
var overview = ""
var imagemovie :UIImage?
override func viewDidLoad() {
super.viewDidLoad()
movieTitle.text = titlemovie
movieOverview.text = overview
movieImage.image = imagemovie
}
}
Here is the result when I clicked the button .
The problem is you don't update you're global properties when selecting each of you're row,
If you pass data over cell delegate and pass you're cell through delegate, you can pass data from cell like:
customViewController?.titlemovie = cell.movieTitle.text ?? ""
customViewController?.imagemovie = cell.movieImage.image
customViewController?.overview = cell.movieOverview.text ?? ""
of course it would be better to pass you're data model to you're cell. and then share that through you're delegate not share you're cell, like:
protocol CellSubclassDelegate: AnyObject {
func buttonTapped(cell: MovieModel)
}
I have table where I can add some empty cells. Using protocol I can send some data to each cell. When I am looking into the table I can see all the information I sent. My problem happens when try to save date using realm, only save last sent data to cell.
// model:
import UIKit
import RealmSwift
class HITActionModel: Object {
#objc dynamic var seconds: Int = 0
#objc dynamic var color: String = ""
#objc dynamic var name: String = ""
#objc dynamic var id: Int = 0
var parentWorkout = LinkingObjects(fromType: WorkoutModel.self, property: "actionsArray")
}
class WorkoutModel: Object {
#objc dynamic var title: String?
#objc dynamic var rounds: Int = 0
var actionsArray = List<HITActionModel>()
}
//protocol
protocol HITActionCellDelegate {
func action(sec: Int, name: String, id: Int)
}
//custom cell
class HITActionCell: UITableViewCell {
//MARK: - Properties
#IBOutlet weak var changeColorBtn: UIButton!
#IBOutlet weak var actionLabel: UILabel!
#IBOutlet weak var actionNameTextField: UITextField!
var delegate: HITActionCellDelegate?
var numberOfSeconds = 0
var id = 0
//MARK: - Lifecycle
override func awakeFromNib() {
super.awakeFromNib()
selectionStyle = .none
}
//MARK: - Elements setup
func setupElements() {
actionNameTextField.placeholder = "Add name for Action!"
changeColorBtn.backgroundColor = UIColor.neonYellow
actionLabel.text = "Entry seconds for action"
}
#IBAction func addActionSeconds(_ sender: Any) {
numberOfSeconds += 1
actionLabel.text = "\(numberOfSeconds) SECONDS"
delegate?.action(sec: numberOfSeconds, name: actionNameTextField.text ?? "", id: self.id)
}
#IBAction func reduceActionSeconds(_ sender: Any) {
if numberOfSeconds > 0 {
numberOfSeconds -= 1
actionLabel.text = "\(numberOfSeconds) SECONDS"
delegate?.action(sec: numberOfSeconds, name: actionNameTextField.text ?? "", id: self.id)
}
}
}
// From here I send data using Protocol to viewController :
import UIKit
import RealmSwift
class AddActionViewController: UIViewController {
//MARK: - Properties
let workout = WorkoutModel()
let action = HITActionModel()
let realm = try! Realm()
var numberOfRounds = 0
#IBOutlet weak var workoutNameTextField: UITextField!
#IBOutlet weak var workoutNameLabel: UILabel!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var roundsLabel: UILabel!
#IBOutlet weak var addRounds: UIButton!
#IBOutlet weak var reduceRounds: UIButton!
#IBOutlet weak var saveButton: UIButton!
#IBOutlet weak var cancelButton: UIButton!
#IBOutlet weak var addActionButton: UIButton!
//MARK:- Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
print(Realm.Configuration.defaultConfiguration.fileURL)
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
tableView.register(UINib(nibName: Const.UI.NibName.hiActionCell, bundle: nil), forCellReuseIdentifier: Const.UI.CellIdentifier.hiActionCell)
}
//MARK:- Elements setup
func setupUI() {
view.backgroundColor = UIColor.black
title = Const.NameString.workouts
addActionButton.setTitle(Const.NameString.addAction, for: .normal)
addActionButton.tintColor = UIColor.black
addActionButton.titleLabel?.font = UIFont.textStyle9
workoutNameLabel.text = Const.NameString.workoutName
workoutNameLabel.font = UIFont.textStyle7
workoutNameLabel.textColor = UIColor.white
workoutNameTextField.textColor = UIColor.black
workoutNameTextField.font = UIFont.textStyle8
roundsLabel.text = Const.NameString.startingRounds
roundsLabel.font = UIFont.textStyle9
roundsLabel.textColor = UIColor.black
roundsLabel.textAlignment = .center
}
#IBAction func saveButtonAction(_ sender: Any) {
if workoutNameTextField.text != "" {
workout.title = workoutNameTextField.text!
workout.rounds = numberOfRounds
save(workout)
self.dismiss(animated: true, completion: nil)
} else {
let myalert = UIAlertController(title: "Message", message: "You forgot something to add ;) (name, rounds, seconds)", preferredStyle: UIAlertController.Style.alert)
myalert.addAction(UIAlertAction.init(title: "I'm guilty", style: .default, handler: nil))
self.present(myalert, animated: true)
}
}
func save(_ workout: WorkoutModel) {
do {
try realm.write {
realm.add(workout)
}
} catch {
print(error.localizedDescription)
}
}
#IBAction func cancelButtonAction(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
#IBAction func addActionButtonPressed(_ sender: Any) {
workout.actionsArray.append(action)
tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: workout.actionsArray.count - 1, section: 0)], with: .fade)
tableView.endUpdates()
}
#IBAction func addRoundsBtn(_ sender: Any) {
numberOfRounds += 1
roundsLabel.text = "\(numberOfRounds) ROUNDS"
}
#IBAction func reduceRoundsBtn(_ sender: Any) {
if numberOfRounds > 0 {
numberOfRounds -= 1
roundsLabel.text = "\(numberOfRounds) ROUNDS"
}
}
}
//MARK:- Setup TextFieldDelegate Method
extension AddActionViewController: UITextFieldDelegate {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
workoutNameTextField.resignFirstResponder()
return true
}
}
//Quick guide implementation for showing and deleting cells
extension AddActionViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return workout.actionsArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: Const.UI.CellIdentifier.hiActionCell) as? HITActionCell else {
return UITableViewCell()
}
cell.delegate = self
cell.setupElements()
cell.id = indexPath.row
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
workout.actionsArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
if (editingStyle == .insert) {
print("test")
}
}
extension AddActionViewController: HITActionCellDelegate {
func action(sec: Int, name: String, id: Int) {
action.name = name
action.seconds = sec
action.id = id
}
}
If could someone help me, It would be greet for me :)
I am using BEMcheckbox. when i click it, it animates and show a hidden label but when I scroll my tableview my checkbox is automatically deselected. also when I scroll it doesn't select any checkbox automatically. what I want is when I scroll my tableview the checkbox which are checked remains checked and which are unchecked remains unchecked. my code is below. my view controller class.
class markAttendanceViewController: UIViewController , UITableViewDataSource , UITableViewDelegate{
#IBAction func selectall(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
checkImageView.isHidden = false
checkboxLabel.layer.borderColor = UIColor.blue.cgColor
} else{
checkImageView.isHidden = true
checkboxLabel.layer.borderColor = UIColor.lightGray.cgColor
}
table.reloadData()
}
#IBOutlet weak var checkImageView: UIImageView!
#IBOutlet weak var checkboxLabel: UILabel!
#IBAction func backToAttendanceView(_ sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var controller: UIViewController!
controller = storyboard.instantiateViewController(withIdentifier: "listViewController") as! listViewController
(controller as! listViewController).receivedString = "Mark Attendance"
let navController = UINavigationController(rootViewController: controller)
let revealController = self.revealViewController() as! RevealViewController
revealController.rightViewController = navController
revealController.rightViewController.view.addGestureRecognizer(revealController.panGestureRecognizer())
self.present(revealController, animated: true, completion: nil)
}
#IBOutlet weak var table: UITableView!
#IBOutlet weak var button: UIButton!
//var items:Array = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.setNavigationBarHidden(true, animated: true)
checkboxLabel.layer.borderWidth = 1
checkboxLabel.layer.borderColor = UIColor.lightGray.cgColor
// items = ["Dashboard","Mark Attendance","Update Attendance","delete Attendance","Time Table","Academic Calendar","Reports","About Us","Logout","rbivwe","whefo","ewsow","webkgwo","wbiebfkwbei","ejwvabei","vdkgdvkJDB"]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 20
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "attendanceTableViewCell") as! attendanceTableViewCell
// cell.studentname?.text = items[indexPath.row]
cell.serialnumber?.text = "\(indexPath.row + 1)"
if button.isSelected {
cell.present.isHidden = false
cell.box.setOn(true, animated: true)
} else
{
cell.box.setOn(false, animated: false)
cell.present.isHidden = true
}
return cell
}
}
My tableview cell class.
class attendanceTableViewCell: UITableViewCell,BEMCheckBoxDelegate {
#IBOutlet weak var present: UILabel!
#IBOutlet weak var box: BEMCheckBox!
#IBOutlet weak var studentname: UILabel!
#IBOutlet weak var serialnumber: UILabel!
#IBOutlet weak var view: UIView!
override func awakeFromNib() {
box.delegate = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
view.layer.masksToBounds = false
view.layer.cornerRadius = 2.0
view.layer.shadowOffset = CGSize(width: -1, height: 1)
view.layer.shadowOpacity = 0.2
// Configure the view for the selected state
}
func didTap(_ checkBox: BEMCheckBox) {
if box.on {
present.isHidden = false
} else {
present.isHidden = true
}
}
}
If someone still need a solution for this. The only way I got it work is to add checkBox state each time you tap on it and then check the state in cellForRowAt function. My suggestion:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, BEMCheckBoxDelegate {
//...
var checkboxesState: [Int: Bool] = [:]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = mainTableView.dequeueReusableCell(withIdentifier: "productCell", for: indexPath) as! ProductCell
cell.checkBox.delegate = self
cell.checkBox.tag = indexPath.row
if let isOn = checkboxesState[indexPath.row] {
if isOn {
cell.checkBox.on = true
} else {
cell.checkBox.on = false
}
} else {
cell.checkBox.on = false
}
//... other code
return cell
}
func didTap(_ checkBox: BEMCheckBox) {
checkboxesState.updateValue(checkBox.on, forKey: checkBox.tag)
}
//...
}
When I search in my searchbar, I want to click on a result and then go to another view controller. I found a similar queston on this site (Swift Search Result Controller in search results segue to another view controller) but it didn't worked out for me.
With my current code there is a working segue, but it is the table view segue (instead of the results segue).
Does someone know how I do this and explain it in an easy way?
Here's my tableviewcontroller code:
class elementstableviewcontroller: UITableViewController,
UISearchResultsUpdating{
var namen = ["Waterstof","Helium","Litium"]
var searchcontroller: UISearchController!
var resultsController: UISearchController!
var filterednamen = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.searchcontroller = UISearchController(searchResultsController: nil)
self.tableView.tableHeaderView = self.searchcontroller.searchBar
self.searchcontroller.searchResultsUpdater = self
self.searchcontroller.dimsBackgroundDuringPresentation = false
definesPresentationContext = true
self.navigationItem.hidesBackButton = false;
self.navigationController?.isNavigationBarHidden = false
}
func updateSearchResults(for searchController: UISearchController) {
self.filterednamen = self.namen.filter { (naam:String) -> Bool in
if naam.lowercased().contains(self.searchcontroller.searchBar.text!.lowercased()) {
return true
}else{
return false
}
}
self.tableView.reloadData()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if !searchcontroller.isActive || searchcontroller.searchBar.text == "" {
return self.namen.count
}else {
return self.filterednamen.count
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomCell
cell.name.text = namen[indexPath.row]
if !searchcontroller.isActive || searchcontroller.searchBar.text == "" {
cell.name.text = self.namen[indexPath.row]
}else{
cell.name.text = self.filterednamen[indexPath.row]
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex2 = indexPath.row
performSegue(withIdentifier: "segue2", sender: self)
}
}
and here's my second view controller code:
import UIKit
import GoogleMobileAds
class Elementenuitgelegd: UIViewController, GADBannerViewDelegate{
#IBOutlet var banner: GADBannerView!
#IBOutlet var uitleg5: UILabel!
#IBOutlet var groep: UILabel!
#IBOutlet var periode: UILabel!
#IBOutlet var uitleg4: UILabel!
#IBOutlet var uitleg3: UILabel!
#IBOutlet var uitleg2: UILabel!
#IBOutlet var uitleg1: UILabel!
#IBOutlet var titlelabel: UILabel!
var distance: Double = 0;
var speed: Double = 0;
var time: Double = 0;
override func viewDidLoad() {
super.viewDidLoad()
titlelabel.text = namen[myIndex2]
uitleg1.text = afkortingen[myIndex2]
uitleg2.text = atoommassas[myIndex2]
uitleg3.text = atoomnummers[myIndex2]
uitleg4.text = electronenconfig[myIndex2]
periode.text = periodes[myIndex2]
groep.text = groepen[myIndex2]
self.navigationItem.hidesBackButton = true;
self.navigationController?.isNavigationBarHidden = true
//banner
let request = GADRequest()
request.testDevices = [kGADSimulatorID]
banner.adUnitID = "ca-app-pub-8478021432040036/4295805958"
banner.rootViewController = self
banner.delegate = self
banner.load(request)
//keyboard weg deel 1
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(startscreen.dismissKeyboard))
//Uncomment the line below if you want the tap not not interfere and cancel other interactions.
//tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//keyboardweg deel 2
func dismissKeyboard() {
view.endEditing(true)
}
}
Here's my customcell controller code:
import UIKit
class CustomCell: UITableViewCell {
#IBOutlet var name: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
[First(tableview),second(searching for Neon and clicking on it), third(getting hydrogen("waterstof" in Dutch)1
I'm trying to pass data (title, ingredients, steps, image) from the selected table cell to a new view controller. But I don't know how to do that. I got lots of errors, so now I'm starting again. Can anyone help me? I'm new to coding. Thanks:-) My code:
VIEWCONTROLLER.SWIFT
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var recipes = [Recipe]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
override func viewDidAppear(animated: Bool) {
fetchAndSetResults()
tableView.reloadData()
}
func fetchAndSetResults(){
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Recipe")
do {
let results = try context.executeFetchRequest(fetchRequest)
self.recipes = results as! [Recipe]
} catch let err as NSError {
print(err.debugDescription)
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("RecipeCell") as? RecipeCell {
let recipe = recipes[indexPath.row]
cell.configureCell(recipe)
return cell
} else {
return RecipeCell()
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return recipes.count
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "RecipeDetail") {
//I WANT TO PASS THE DATA FROM THE TABLE CELL TO THE NEW VIEW CONTROLLER (RECIPEDETAILVC)
}
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext
context.deleteObject(recipes[indexPath.row])
app.saveContext()
recipes.removeAtIndex(indexPath.row)
tableView.reloadData()
}
}
}
CREATERECIPE.SWIFT
class CreateRecipeVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var recipeTitle: UITextField!
#IBOutlet weak var recipeIngredients: UITextField!
#IBOutlet weak var recipeSteps: UITextField!
#IBOutlet weak var recipeImage: UIImageView!
#IBOutlet weak var addRecipeBtn: UIButton!
var imagePicker: UIImagePickerController!
override func viewDidLoad() {
super.viewDidLoad()
imagePicker = UIImagePickerController()
imagePicker.delegate = self
recipeImage.layer.cornerRadius = 5.0
recipeImage.clipsToBounds = true
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
imagePicker.dismissViewControllerAnimated(true, completion: nil)
recipeImage.image = image
}
#IBAction func addImage(sender: AnyObject!) {
presentViewController(imagePicker, animated: true, completion: nil)
}
#IBAction func createRecipe(sender: AnyObject!) {
if let title = recipeTitle.text where title != "" {
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let context = app.managedObjectContext
let entity = NSEntityDescription.entityForName("Recipe", inManagedObjectContext: context)!
let recipe = Recipe(entity: entity, insertIntoManagedObjectContext: context)
recipe.title = title
recipe.ingredients = recipeIngredients.text
recipe.steps = recipeSteps.text
recipe.setRecipeImage(recipeImage.image!)
context.insertObject(recipe)
do {
try context.save()
} catch {
print("Could not save recipe")
}
self.navigationController?.popViewControllerAnimated(true)
}
}
}
RECIPEDETAILVC.SWIFT
import UIKit
import CoreData
class RecipeDetailVC: UIViewController {
#IBOutlet weak var recipeImage: UIImageView!
#IBOutlet weak var recipeTitle: UILabel!
#IBOutlet weak var recipeIngredients: UILabel!
#IBOutlet weak var recipeSteps: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//I WANT TO DISPLAY THE CORE DATA INFORMATION FROM THE TABLE CELL I SELECTED.
}
}
RECIPECELL.SWIFT
class RecipeCell: UITableViewCell {
#IBOutlet weak var recipeTitle: UILabel!
#IBOutlet weak var recipeImage: UIImageView!
func configureCell(recipe: Recipe) {
recipeTitle.text = recipe.title
recipeImage.image = recipe.getRecipeImage()
}
}
You need to track which item the person clicked.
var mySelection: Int?
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
mySelection = indexPath.row
}
Then, use that when doing the segue.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "RecipeDetail") {
//I WANT TO PASS THE DATA FROM THE TABLE CELL TO THE NEW VIEW CONTROLLER (RECIPEDETAILVC)
let recipeDetailControler = segue.destinationViewController as! RecipeDetailViewController
if let mySelection = mySelection {
let recipe = recipes[mySelection]
// add this function to your
recipeDetailControler.configureRecipeData(recipe)
}
}
}
Add this function to RecipeDetailViewController:
func configureRecipeData(recipe: Recipe) {
// IMPLEMENT ME
}