Storing an NSURL in a global variable - swift

I am currently working on an app in which the user can save their favorite place to a table view and by selecting a row in that table view it opens a new view controller with a web view. In that web view, I want it to display a google search of the place that the user has added to the table.
I've tried using NSUserDefaults to try and save the URL of the google search but I was unable to access it from within a different view controller file.
I've researched on google but have still been unable to find exactly what I'm looking for.
I wanted to find out if anyone knows how to save a URL and access it from within a different file to be the URL that the web view displays.
Here's my code:
SecondViewController(Has a table view with the names of the places that the user saves, selecting should open a view with a google search of the name of the place that the user saved)
import UIKit
var favoritePlaces = [String]()
class SecondViewController: UIViewController, UITableViewDelegate, UITextFieldDelegate, UITableViewDataSource {
#IBAction func alertButtonPressed(sender: AnyObject) {
let addNewPlaceAlert = UIAlertController(title: "Add A Favorite Place", message: "Enter the name of the place here", preferredStyle: .Alert)
let saveAction = UIAlertAction(title: "Done", style: .Default) { (alert: UIAlertAction!) -> Void in
NSLog("You pressed button OK")
addNewPlaceAlert.dismissViewControllerAnimated(true, completion: nil)
let textField = addNewPlaceAlert.textFields![0] as UITextField
favoritePlaces.append(textField.text!)
self.favoritePlacesTable.reloadData()
NSUserDefaults.standardUserDefaults().setObject(favoritePlaces, forKey: "favoritePlaces")
}
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (alert: UIAlertAction!) -> Void in
NSLog("You pressed button OK")
}
addNewPlaceAlert.addAction(saveAction)
addNewPlaceAlert.addAction(cancelAction)
addNewPlaceAlert.addTextFieldWithConfigurationHandler { (textField: UITextField!) in
}
presentViewController(addNewPlaceAlert, animated: true, completion: nil)
}
func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
if buttonIndex == 1 {
favoritePlaces.append(alertView.textFieldAtIndex(0)!.text!)
favoritePlacesTable.reloadData()
}
}
#IBOutlet var favoritePlacesTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
if NSUserDefaults.standardUserDefaults().objectForKey("favoritePlaces") != nil {
favoritePlaces = NSUserDefaults.standardUserDefaults().objectForKey("favoritePlaces") as! [String]
}
// Do any additional setup after loading the view, typically from a nib.
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
favoritePlacesTable.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
print("Row: \(row)")
print(favoritePlaces[row] as String)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section:Int) -> Int {
return favoritePlaces.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell? = favoritePlacesTable.dequeueReusableCellWithIdentifier("Cell")! as UITableViewCell
cell!.textLabel?.text = favoritePlaces[indexPath.row]
if (cell != nil)
{
cell = UITableViewCell(style: UITableViewCellStyle.Subtitle,
reuseIdentifier: "Cell")
}
// At this point, we definitely have a cell -- either dequeued or newly created,
// so let's force unwrap the optional into a UITableViewCell
return cell!
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let row = indexPath.row
performSegueWithIdentifier("showContent", sender: row)
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
favoritePlaces.removeAtIndex(indexPath.row)
NSUserDefaults.standardUserDefaults().setObject(favoritePlaces, forKey: "favoritePlaces")
favoritePlacesTable.reloadData()
}
}
override func viewDidAppear(animated: Bool) {
favoritePlacesTable.reloadData()
}
}
Favorite Place View Controller(The view that opens once a user selects a row)
import UIKit
class FavoritePlaceViewController: UIViewController {
enter code here
#IBOutlet var favoritePlaceWV: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
let url = NSURL(string: "https://www.google.com")!
favoritePlaceWV.loadRequest(NSURLRequest(URL: url))
// Do any additional setup after loading the view.
NSUserDefaults.standardUserDefaults().objectForKey("secondUrl")
}
`enter code here`override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

I used a struct to define base urls for different end points as follows. This is accessible to all models and view controllers as well, according to my need. I guess this was your requirement.
struct URL {
private static let BaseURL = "https://yourdomain.com/urlendpoint/api/"
private static let CurrentVersion = "v202/json/en/"
private static let year15 = "2015/"
private static let currentYear = "2016/"
//MARK:- Update URl
static var UpdateURL: String {
return BaseURL + CurrentVersion + currentYear + "update.json"
}
static var FirstURL: [String] {
var urls: [String] = []
for i in 0...11 {
urls.append(BaseURL + CurrentVersion + currentYear + + FirstMonth + String(i) + ".json")
}
return urls
}
static var SecondURL: String {
return BaseURL + CurrentVersion + "second.json"
}
//MARK:- Dream
static var ThirdURL: String {
return BaseURL + CurrentVersion + "third_results.json"
}
static var FourthURL: String {
return BaseURL + CurrentVersion + "fourth.json"
}
static var FifthURL: String {
return BaseURL + CurrentVersion + currentYear + "fifth.json"
}
}

Related

Filtering Image Data with Search Bar

I am trying to filter the data from API. The is successful loaded into view controller with table view cell . This is a movie applications . I am trying to filter the data based on the user type into the text box . I mentioned in the code filter my the title of the movie but The code is only able to filter the title and overview of the movie but the Image fields remain unfiltered such as image , overview etc. Here is the struct model .
import Foundation
struct Movie: Decodable {
let originalTitle: String
let overview: String
let posterPath: String
enum CodingKeys: String, CodingKey {
case originalTitle = "original_title"
case overview
case posterPath = "poster_path"
}
}
Here is the protocol class code .
import Foundation
class MoviePresenter: MoviePresenterProtocol {
private let view: MovieViewProtocol
private let networkManager: NetworkManager
var movies = [Movie]()
private var cache = [Int: Data]()
var rows: Int {
return movies.count
}
init(view: MovieViewProtocol, networkManager: NetworkManager = NetworkManager()) {
self.view = view
self.networkManager = networkManager
}
func getMovies() {
let url = "https://api.themoviedb.org/3/movie/popular?language=en-US&page=3&api_key=6622998c4ceac172a976a1136b204df4"
networkManager.getMovies(from: url) { [weak self] result in
switch result {
case .success(let response):
self?.movies = response.results
self?.downloadImages()
DispatchQueue.main.async {
self?.view.resfreshTableView()
}
case .failure(let error):
DispatchQueue.main.async {
self?.view.displayError(error.localizedDescription)
}
}
}
}
func getTitle(by row: Int) -> String? {
return movies[row].originalTitle
}
func getOverview(by row: Int) -> String? {
return movies[row].overview
}
func getImageData(by row: Int) -> Data? {
return cache[row]
}
private func downloadImages() {
let baseImageURL = "https://image.tmdb.org/t/p/w500"
let posterArray = movies.map { "\(baseImageURL)\($0.posterPath)" }
let group = DispatchGroup()
group.enter()
for (index, url) in posterArray.enumerated() {
networkManager.getImageData(from: url) { [weak self] data in
if let data = data {
self?.cache[index] = data
}
}
}
group.leave()
group.notify(queue: .main) { [weak self] in
self?.view.resfreshTableView()
}
}
}
Here is the 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 = ""
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 == 1{
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
return movies.originalTitle.lowercased().contains(searchText.lowercased())
})
}
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.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
}
}
Here is the screenshot of the result .
Caching image in tableview is a little bit tricky, and you may get problem when the cell changes or reusing itself,
that's cause you see same image when texts are different.
there are 2 famous package you can use it for you're problem and it's easy to use with a lot of options.
1- Kingfisher
2- SDWebImage

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]

How to get the label values from multiple selected cells in a UITableView and pass them to a different ViewController swift

Sorry, I'm a noob,
I am a bit stuck. I have been researching this for awhile and cannot find anything to help.
So, my problems is:
I have a Table View controller with a bunch of Cells (Depending on users contact address book). These Cells contain the users contacts information (Name and #) users can select up to 3 cells (Contacts).
That all works fine, I just need to know how to get the name and # labels data from each cell so I can display that information in another View Controller (CAContactsList) when I press the "Done" button (which I'm also stumped with).
My Current Table View Controller Class:
class AddContactsListTableView: UITableViewController {
var contacts = [FetchedContact]()
override func viewDidLoad() {
super.viewDidLoad()
fetchContacts()
}
private func fetchContacts() {
print("Attempting to fetch contacts")
let store = CNContactStore()
store.requestAccess(for: .contacts) { (granted, error) in
if let error = error {
print("failed to request access", error)
return
}
if granted {
print("access granted")
let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey]
let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor])
do {
try store.enumerateContacts(with: request, usingBlock: { (contact, stopPointer) in
print(contact.givenName)
self.contacts.append(FetchedContact(firstName: contact.givenName, lastName: contact.familyName, telephone: contact.phoneNumbers.first?.value.stringValue ?? ""))
})
} catch let error {
print("Failed to enumerate contact", error)
}
} else {
print("access denied")
}
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// return the number of rows
return contacts.count
}
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
//Max Number of contacts allowed to be selected
let limit = 3
if let selectedRows = tableView.indexPathsForSelectedRows {
if selectedRows.count == limit {
let alertController = UIAlertController(title: "Oops", message: "Sorry, but you are limited to only \(limit) Contacts", preferredStyle: UIAlertController.Style.alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: {action in}))
self.present(alertController, animated: true, completion: nil)
return nil
}
}
return indexPath
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "AddContactsCell"
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? AddContactsCell
// Configure the cell...
cell?.NamesLabel.text = contacts[indexPath.row].firstName + " " + contacts[indexPath.row].lastName
cell?.NumberLabel.text = contacts[indexPath.row].telephone
return cell!
}
}
My Current Cell Class:
class AddContactsCell: UITableViewCell {
//Mark Properties
#IBOutlet weak var NamesLabel: UILabel!
#IBOutlet weak var NumberLabel: UILabel!
#IBOutlet weak var ButtonSelector: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// update UI with Checkmark when Selected
accessoryType = selected ? .checkmark : .none
}
}
And my Fetched Contacts Class
struct FetchedContact {
var firstName: String
var lastName: String
var telephone: String
}
Any help would be Greatly Appreciated!
Override the prepare(for segue: UIStoryboardSegue, sender: Any?) in the AddContactsListTableView class where you can pass the selected contacts to the next view controller.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Pass the selected object to the new view controller.
if let selectedRows = tableView.indexPathsForSelectedRows {
let selectedContacts = selectedRows.map{contacts[$0.row]}
let newVC = segue.destination as! NewViewController
newVC.contacts = selectedContacts
}
}
See this tutorial for more.
So basically you are already on the right track querying the table view's indexPathsForSelectedRows since it will contain the indices you need to filter your contacts for. The selected contacts should be:
guard let selectedIndices = tableView.indexPathsForSelectedRows else { return }
let selectedContacts = selectedIndices.map { contacts[$0.item] }
[Edit]: Use a more concise version

fetch data from firebase and use textfield for preview and update purposes

I want to use the same objects of one ViewController for saving into Firebase and for fetching saved data to preview and update if necessary.
Initially I used textfield in static cells it worked pretty well, but fail to insert text in textfield in dynamic cell.
When I call print function for the textfield in console it prints out correct value, but doesn't show anything on screen of simulator. I even tried to use simple strait text string to put it into textfield, but unsuccessful.
here is related code from TextMessageViewController, which i use for sending data to Firebase through textfields in dynamical tablecells
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TextInputTableViewCell = receiverEmailTableView.dequeueReusableCell(withIdentifier: "ReceiverEmail") as! TextInputTableViewCell!
cell.recepientEmailTF.delegate = self
cell.recepientEmailTF.tag = indexPath.row
return cell
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {
if MyGlobalVariables.emails.count <= 3 {
print("tag master = \(textField.tag)")
switch textField.tag {
case 0:
if MyGlobalVariables.emails.endIndex == 0 {
MyGlobalVariables.emails.append(textField.text!)
}
MyGlobalVariables.emails[0] = textField.text!
case 1:
if MyGlobalVariables.emails.endIndex == 1 {
MyGlobalVariables.emails.append(textField.text!)
}
MyGlobalVariables.emails[1] = textField.text!
case 2:
if MyGlobalVariables.emails.endIndex == 2 {
MyGlobalVariables.emails.append(textField.text!)
}
MyGlobalVariables.emails[2] = textField.text!
default:
print("exceeded")
}
DispatchQueue.main.async {
self.receiverEmailTableView.reloadData()
}
} else {
print("exceeded emails limit, add alert")
}
}
Portion of code from TextPreviewViewController from where I want to get firebase data and add it to texfields. This viewcontroller is connected to preview viewcontroller in storyboard
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let edit = UITableViewRowAction(style: .default, title: "Edit") { (action, indexPath) in
let newMessageVC = self.storyboard?.instantiateViewController(withIdentifier: "TextMessage") as? TextMessageViewController
newMessageVC?.modalPresentationStyle = .overCurrentContext
self.present(newMessageVC!, animated: true, completion: {
let updateButton = newMessageVC?.saveOrUpdateButton
updateButton?.titleLabel?.text = "Update"
let messageBody = newMessageVC?.messageTV
let dateField = newMessageVC?.tergetDateTF
let action = MyGlobalVariables.refMessages.child(MyGlobalVariables.uidUser!)
// CONCERN POINT: from here->
let cell1: TextInputTableViewCell = newMessageVC?.receiverEmailTableView.dequeueReusableCell(withIdentifier: "ReceiverEmail") as! TextInputTableViewCell!
cell1.recepientEmailTF.delegate = self
cell1.recepientEmailTF.allowsEditingTextAttributes = true
let texfielf = cell1.recepientEmailTF
MyGlobalVariables.emails.removeAll()
MyGlobalVariables.emails = ["","",""]
// cell1.recepientEmailTF.text = "Suka blyat" <- even this simple text doesnt appear
MyGlobalVariables.emails[0].append(self.messages[indexPath.row].email1!)
texfielf?.text = MyGlobalVariables.emails[0]
//cell1.recepientEmailTF.text = MyGlobalVariables.emails[0] <- this code also doesnt work
MyGlobalVariables.emails[1].append(self.messages[indexPath.row].email2!)
texfielf?.text = self.messages[indexPath.row].email2!
MyGlobalVariables.emails[2].append(self.messages[indexPath.row].email3!)
texfielf?.text = self.messages[indexPath.row].email3!
DispatchQueue.main.async {
newMessageVC?.receiverEmailTableView.reloadData()
}
//CONCERN POINT: ->up to here
messageBody?.text = self.messages[indexPath.row].message!
dateField?.text = self.messages[indexPath.row].setupDate!
if let autoID2 = self.messages[indexPath.row].autoID {
MyGlobalVariables.messageForUpdate1.append(autoID2) }
})
}
return [edit]
}
My UITableViewCell class
public class TextInputTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var recepientEmailTF: UITextField!
override public func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override public func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}}
I would appreciate any help or advices.

UI TableView cell opening a new view with multiple data using coredata in swift

as a beginner in iOS and Swift, I have a project that has to have a tableview with multiple cells, in which every cell contains several data types. i.e. Strings, dates etc., where in one view controller, there is the table view for viewing the cells, the second view controller is for creating a cell and entering the data, and the third view is for displaying the same data when clicking the cell. I've decided to store all of that using coredata since I was told it's most efficient and simple for beginners. I've used several tutorials on this matter but none of them handle this type of problem I have. Best example is how the Contact list works on iOS.
The code I've done so far is this:
var titleCellList = [NSManagedObject]()
var infoCellList = [NSManagedObject]()
class CellsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var cellsTableView: UITableView!
//MARK: Default Functions
override func viewDidLoad() {
super.viewDidLoad()
title = "\"Lists\""
cellsTableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
// Do any additional setup after loading the view.
}
// MARK: UITableViewDataSource
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TitleCellList.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell
let cellTitle = titleCellList[indexPath.row]
cell.textLabel!.text = cellTitle.valueForKey("title") as? String
return cell
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(animated: Bool) {
cellsTableView.reloadData()
}
//MARK: Storing CoreData
func saveName(name: String) {
//1
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let entity = NSEntityDescription.entityForName("Data", inManagedObjectContext: managedContext)
let title = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)
//3
title.setValue(name, forKey: "title")
//4
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
//5
titleCellList.append(title)
}
//MARK: Fetching CoreData
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//1
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let fetchRequest = NSFetchRequest(entityName:"Data")
//3
var error: NSError?
let fetchedResults = managedContext.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObject]
if let results = fetchedResults {
titleCellList = results
} else {
println("Could not fetch \(error), \(error!.userInfo)")
}
}
// MARK: Table Editing Methods
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 appDel:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext!
context.deleteObject(titleCellList[indexPath.row] as NSManagedObject)
titleCellList.removeAtIndex(indexPath.row)
context.save(nil)
cellsTableView.reloadData()
}
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
let row = indexPath.row
println("Row: \(row)")
println(titleCellList[row])
performSegueWithIdentifier("checkCellSegue", sender: self)
}
Second View Controller (the one for creating a cell with data)
class AddNewViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var titleTextField: UITextField!
#IBOutlet var shortInfoTextView: UITextView!
//MARK: Default Functions
override func viewDidLoad() {
super.viewDidLoad()
self.titleTextField.delegate = self
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
#IBAction func addDataButtonPressed(sender: UIButton) {
if titleTextField.text != "" {
CellsViewController().saveName(titleTextField.text)
titleTextField.text = ""
shortInfoTextView.text = ""
println("New title Added!")
}else {
println("No empty titles allowed!")
}
}
Now, most of this code is from a tutorial, and when I tried adding other data entity's, it didn't work. In the datamodel I currently have only 1 entity named "Data" which contains 4 models. So, to sum it up, I need to store 4 data models in one entity and load them on a different view controller when clicking on a cell which of course, has a title that the user wrote. And just to note, I've spent hours searching online for an answer so this is my last line so to say.
Any help would be greatly appreciated.
So, here is the one approach I used on this little issue. I basically just pass arguments with the prepareForSegue method, and inside of it I just pass the data I want to use in the other class/VC.
The Code:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
// Setter for Second VC, destination path --> var declarations in Second VC
if segue.identifier == "checkCellSegue" {
let destination = segue.destinationViewController as! SecondViewController
if let indexPath = self.tableView?.indexPathForCell(sender as! UITableViewCell) {
let object = fetchedResultsController?.objectAtIndexPath(indexPath) as? Data
destination.cellTitle = object?.cellTitle
destination.textViewInfo = object?.textViewInfo
destination.timerValue = object?.timerValue
}
}
So, first we declare the destination which is the name of our Second VC or whatever you named it. Then, since I am accessing data trough a TableView cell we need to fetch my CoreData Entity with the indexPath. After that the final declaration is the Model Class which has all the data values from the entity, which will work like a singleton.
destination.cellTitle // --> in the 2.nd VC we declared a new var called cellTitle, var cellTitle:String
object?.cellTitle // --> in the model class "Data.swift" the declaration is #NSManaged var cellTitle:String
So, thats it. I am still a little newbie on iOS so if there are any mistakes, just say so.