Persistent data in Swift - ios

I am currently experimenting with persistent data in swift, but I am having trouble saving this data and retrieving it back again. Basically I have two text fields, and when the user presses the submit button then the entry will be saved to a UITable, here the user will be able to move the entries in the table around or delete them if they so wish. My main problem is saving and loading this data.
Taskmanager.swift -- Here I have my basic types stored
import Foundation
import UIKit
var taskMgr: TaskManager = TaskManager()
struct task {
var name = "Name"
var year = "Year"
}
//setting data
let defaults = UserDefaults.standard
//defaults.synchronize()
//getting data
class TaskManager: NSObject {
var tasks = [task]()
func addTask(name: String, year: String){
tasks.append(task(name: name, year: year))
}
}
ThirdViewController.swift -- Here I have stored my table and its functions, I also have a rough sketch of save and load data functions.
import Foundation
import UIKit
class ThirdViewController:UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
#IBAction func deleteT(_ sender: Any) {
if(tableView.isEditing == true){
tableView.setEditing(false, animated: true)
}else{
tableView.setEditing(true, animated: true)
}
}
func saveData() {
let data = NSMutableData()
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0]
let file = (path as NSString).appendingPathComponent("Persistent.plist")
//2
let archiver = NSKeyedArchiver(forWritingWith: data)
archiver.encode(G, forKey: "name")
archiver.endode(year, forKey: "year")
archiver.finishEncoding()
data.write(toFile: file, atomically: true)
}
func loadData() {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let path = paths[0]
let file = (path as NSString).appendingPathComponent("Persistent.plist")
// 1
if FileManager.default.fileExists(atPath: file) {
if let data = NSData(contentsOfFile: file) {
let unarchiver = NSKeyedUnarchiver(forReadingWith: data as Data)
name = unarchiver.decodeObjectForKey("name") as! [String]
year = unarchiver.decodeObjectForKey("year") as! [String]
unarchiver.finishDecoding()
}
}
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.reloadData()
loadData()
}
override func viewWillAppear(_ animated: Bool) {
self.tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return taskMgr.tasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "TableView")
//Assign the contents of our var "items" to the textLabel of each cell
cell.textLabel!.text = taskMgr.tasks[indexPath.row].name
cell.detailTextLabel!.text = taskMgr.tasks[indexPath.row].year
//cell.editing = tableView(tableView, canMoveRowAtIndexPath: indexPath)
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){
if (editingStyle == UITableViewCellEditingStyle.delete){
taskMgr.tasks.remove(at: indexPath.row)
tableView.reloadData()
}
}
}
FourthViewController.swift -- Here I have my textfields and buttons and how I am adding my entries to the table.
import Foundation
import UIKit
class FourthViewController: UIViewController, UITextFieldDelegate{
#IBOutlet var addT: UITextField!
#IBOutlet var addY: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func confTask(_ sender:UIButton){
if (addT.text == ""){
}else{
//add record
let name: String = addT.text!
let Year: String = addY.text!
//taskMgr.addTask(name:name)
taskMgr.addTask(name:name, year:Year)
}
//dismiss keyboard and reset fields
self.view.endEditing(true)
addT.text = nil
addY.text = nil
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool{
textField.resignFirstResponder()
return true
}
}

I have created some sample code using NSUserDefaults for persisting the tasks. It is a fairly simple example, as long as you are just experimenting, and only want to have less than a 100 elements, it should be fine. Using the code below you should be able to display, remove and save tasks.
However, in the future, i would highly recommend you to read more into Core Data. There are many great tutorials out there, like this one.
I have created a Task object model, and TaskManager for reading, saving and removing tasks.
import Foundation
// Task Data Model
class Task: NSObject, NSCoding {
let name: String
let year: String
required init(name: String, year: String) {
self.name = name
self.year = year
}
required init(coder decoder: NSCoder) {
self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
self.year = decoder.decodeObject(forKey: "year") as? String ?? ""
}
func encode(with coder: NSCoder) {
coder.encode(name, forKey: "name")
coder.encode(year, forKey: "year")
}
}
class TaskManager {
/// UserDefaults instance
private let defaults = UserDefaults.standard
/// Singleton instance, class **should** be accessed by this property
static let shared = TaskManager()
/// Indetifier of tasks container in `defaults`
private let kTasksIdentifier = "tasks"
/// Add a new task to your container and syncronize it into `defaults`
///
/// - Parameters:
/// - name: Name of the task
/// - year: Year of the task
func save(taskName name: String, year: String) {
let task = Task(name: name, year: year)
// Check if there is already saved tasks
guard let data = defaults.value(forKey: kTasksIdentifier) as? Data, var tasks = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Task] else {
// If not, save it as the first one
syncronizeTasks(tasks: [task])
return
}
tasks.append(task)
syncronizeTasks(tasks: tasks)
}
/// Remove a task at an index
///
/// - Parameters:
/// - index: The index of the removeable task
func remove(at index: Int) {
guard let data = defaults.value(forKey: kTasksIdentifier) as? Data, var tasks = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Task] else {
fatalError("Unable to retrive tasks from defaults")
}
tasks.remove(at: index)
syncronizeTasks(tasks: tasks)
}
/// Read all tasks elements
/// If there are tasks in memory, it returns the one from memory
/// Otherwise reads it from `UserDefaults`
///
/// - Returns: all tasks elements available, return empty array if no elements found
func readAllTasks() -> [Task] {
let data = UserDefaults.standard.value(forKey: kTasksIdentifier)
let allTasks = NSKeyedUnarchiver.unarchiveObject(with: data as! Data)
return allTasks as? [Task] ?? [Task]()
}
private func syncronizeTasks(tasks: [Task]) {
let data = NSKeyedArchiver.archivedData(withRootObject: tasks)
defaults.set(data, forKey: kTasksIdentifier)
defaults.synchronize()
}
}
I have modified your already existing ThirdViewController a bit.
import UIKit
import Foundation
class ThirdViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
/// Your tasks being updated in this collection every time `refreshTasks()` is being called
private var tasks = [Task]()
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.refreshTasks()
self.tableView.reloadData()
}
func refreshTasks() {
self.tasks = TaskManager.shared.readAllTasks()
}
#IBAction func deleteT(_ sender: Any) {
if(tableView.isEditing == true) {
tableView.setEditing(false, animated: true)
} else {
tableView.setEditing(true, animated: true)
}
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
return false
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return tasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.subtitle, reuseIdentifier: "TableView")
//Assign the contents of our var "items" to the textLabel of each cell
cell.textLabel!.text = tasks[indexPath.row].name
cell.detailTextLabel!.text = tasks[indexPath.row].year
//cell.editing = tableView(tableView, canMoveRowAtIndexPath: indexPath)
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath){
if (editingStyle == UITableViewCellEditingStyle.delete) {
self.tableView.beginUpdates()
TaskManager.shared.remove(at: indexPath.row)
refreshTasks()
self.tableView.deleteRows(at: [indexPath], with: .fade)
self.tableView.endUpdates()
}
}
}
And, just in case, edited your FourthViewController too
import Foundation
import UIKit
class FourthViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var addT: UITextField!
#IBOutlet var addY: UITextField!
/// User has pressed `Submit` button
///
/// - Parameter sender: the pressed button
#IBAction func confTask(_ sender: UIButton) {
// Check if textfields are containing text
guard let nameText = addT.text, let yearText = addY.text, !nameText.isEmpty, !yearText.isEmpty else {
print("at least one of the textFields is not filled")
return
}
// Save the tasks
TaskManager.shared.save(taskName: nameText, year: yearText)
//dismiss keyboard and reset fields
self.view.endEditing(true)
addT.text = nil
addY.text = nil
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool{
textField.resignFirstResponder()
return true
}
}

Related

How to fix deleted task being restored in Userdefaultrs

I'm making a TodoList app.
If you swipe a task from the list to delete it and then add a new task, the deleted task will be restored.
Use storyboard and UIKit.
I want to keep it deleted, what should I do? ..
mac 10.15.7
xcode 12.1
import UIKit
class ViewController: UIViewController {
#IBOutlet var tableView: UITableView!
var tasks = [String]()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "リスト"
tableView.delegate = self
tableView.dataSource = self
if !UserDefaults().bool(forKey: "setup") {
UserDefaults().set(true, forKey: "setup")
UserDefaults().set(0, forKey: "count")
}
updateTasks()
}
func updateTasks() {
tasks.removeAll()
guard let count = UserDefaults().value(forKey: "count") as? Int else {
return
}
for x in 0..<count {
if let task = UserDefaults().value(forKey: "task_\(x+1)") as? String {
tasks.append(task)
}
}
tableView.reloadData()
}
#IBAction func didTapAdd() {
let vc = storyboard?.instantiateViewController(identifier: "entry") as! EntryViewController
vc.title = "リストに追加"
vc.update = {
//非同期処理 更新を優先
DispatchQueue.main.async {
self.updateTasks()
}
}
navigationController?.pushViewController(vc, animated: true)
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let vc = storyboard?.instantiateViewController(identifier: "task") as! TaskViewController
vc.title = "リストに追加"
vc.task = tasks[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = tasks[indexPath.row]
return cell
}
//タスクを削除
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
let index = indexPath.row
tasks.remove(at: index)
let userDefaults = UserDefaults.standard
userDefaults.set(tasks, forKey: "tasks")
userDefaults.removeObject(forKey: "tasks")
tableView.reloadData()
}
}
Is remove (at :) different?
import UIKit
class EntryViewController: UIViewController, UITextFieldDelegate {
#IBOutlet var field: UITextField!
var update: (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
field.delegate = self
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "保存", style: .done, target: self, action: #selector(saveTask))
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
saveTask()
return true
}
#objc func saveTask() {
guard let text = field.text, !text.isEmpty else {
return
}
guard let count = UserDefaults().value(forKey: "count") as? Int else {
return
}
let newCount = count + 1
UserDefaults().set(newCount, forKey: "count")
UserDefaults().set(text, forKey: "task_\(newCount)")
update?()
navigationController?.popViewController(animated: true)
}
}
How to save UserDefaults?
The problem I see is; in updateTasks function, you get the tasks from UserDefaults by keys as task_1, task_2 etc. But when deleting a specific task, lets say task_2, you are just removing it from tasks array, not deleting it from UserDefaults. So whenever you call updateTasks function, the deleted task re-appears.
In your EntryViewController, change the saveTask function with following:
#objc func saveTask() {
guard let text = field.text, !text.isEmpty else {
return
}
let tasks = UserDefaults.standard.array(forKey: "tasks") as? [String] ?? []
tasks.append(text)
UserDefaults.standard.set(tasks, forKey: "tasks")
update?()
navigationController?.popViewController(animated: true)
}
In your ViewController, change the following functions:
func updateTasks() {
tasks.removeAll()
tasks = UserDefaults.standard.array(forKey: "tasks") as? [String] ?? []
tableView.reloadData()
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
tasks.remove(at: indexPath.row)
let userDefaults = UserDefaults.standard
userDefaults.set(tasks, forKey: "tasks")
updateTasks()
}

Use of undeclared type 'TrailViewController' - trying to handle item details from list in iOS app

Another issue with learning.
I found this in Apple Dev documentation: THIS
My target is to handle one tap on my list of items. When I click I need to open edit window and handle which row I selected. I trying to put that solution into my code but I have no idea what is TrailViewController (I getting Chinese links at first Google search page). So I decided to put my code there. I getting error:
Use of undeclared type 'TrailViewController'.
They appear after I adding this into my code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedTrail = elements[indexPath.row]
if let viewController = storyboard?.instantiateViewController(identifier: "TrailViewController") as? TrailViewController {
viewController.trail = selectedTrail
navigationController?.pushViewController(viewController, animated: true)
}
}
Full code from file below:
import UIKit
import Firebase
import FirebaseFirestore
class MainViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var listOfItemsTableView: UITableView!
var elements: [Element] = []
override func viewDidLoad() {
super.viewDidLoad()
let db = Firestore.firestore()
db.collection("recipes").whereField("uid", isEqualTo: Auth.auth().currentUser!.uid).addSnapshotListener({ (snapshot, error) in
if let snapshot = snapshot {
var elementsTemp = [Element]()
for doc in snapshot.documents {
if let itemName = doc.get("name") as? String {
elementsTemp.append(Element(name: itemName))
}
}
self.elements = elementsTemp
self.listOfItemsTableView.reloadData()
} else {
if let error = error {
print(error)
}
}
})
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.listOfItemsTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return elements.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "elementCell", for: indexPath) as! ElementCell
cell.elementNameLabel.text = elements[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedTrail = elements[indexPath.row]
if let viewController = storyboard?.instantiateViewController(identifier: "TrailViewController") as? TrailViewController {
viewController.trail = selectedTrail
navigationController?.pushViewController(viewController, animated: true)
}
}
#IBAction func addItemButtonClicked(_ sender: Any) {
self.performSegue(withIdentifier: "toAddItemView", sender: self)
}
}
class Element {
var name = ""
convenience init(name: String) {
self.init()
self.name = name
}
}
Update 1
Ok, I made some progress, but at this moment I can't navigate to EditItemViewController. This is how my code looks now:
import UIKit
import Firebase
import FirebaseFirestore
class MainViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var listOfItemsTableView: UITableView!
var elements: [Element] = []
var element: Element?
override func viewDidLoad() {
super.viewDidLoad()
let db = Firestore.firestore()
db.collection("recipes").whereField("uid", isEqualTo: Auth.auth().currentUser!.uid).addSnapshotListener({ (snapshot, error) in
if let snapshot = snapshot {
var elementsTemp = [Element]()
for doc in snapshot.documents {
if let itemName = doc.get("name") as? String {
elementsTemp.append(Element(name: itemName))
}
}
self.elements = elementsTemp
self.listOfItemsTableView.reloadData()
} else {
if let error = error {
print(error)
}
}
})
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.listOfItemsTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return elements.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "elementCell", for: indexPath) as! ElementCell
cell.elementNameLabel.text = elements[indexPath.row].name
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedElement = elements[indexPath.row]
if let viewController = storyboard?.instantiateViewController(identifier: "EditItemViewControllerID") as? MainViewController {
viewController.element = selectedElement
self.navigationController?.pushViewController(viewController, animated: true)
}
}
#IBAction func addItemButtonClicked(_ sender: Any) {
self.performSegue(withIdentifier: "toAddItemView", sender: self)
}
}
class Element {
var name = ""
convenience init(name: String) {
self.init()
self.name = name
}
}
And how my storyboard looks at this moment:
Maybe I missed something?
Make a UIViewController named TrailViewController and add it as the class for a new UIViewController in your storyboard and you'll no longer get this error:
class TrailViewController: UIViewController {
var trail: Element?
// ...
}
Note: Also, don't forget to add the identifier for the new TrailViewController added in the storyboard as "TrailViewController" to get the UIViewController when calling instantiateViewController(identifier: in didSelectRow and perform navigation successfully.

How to add UserDefaults into a task list - Swift

Iv been trying to add userDefaults to my code and trying to save for example a task so the next time i open the app i can still see the task .
didnt quit understood how userDefaults work.Maybe someone can help me?
taskList VC file:
#IBAction func doneButton_Tapped(_ sender: Any) {
var newTask = taskList()
newTask.name = taskNameField.text!
newTask.dueDate = dueDatePicker.date
newTask.dateCreated = Date()
taskArr.append(newTask)
didCreateTask = true
self.navigationController?.popViewController(animated: true)
}
mainVC file:
struct taskList {
var name: String!
var dateCreated: Date!
var dueDate:Date!
}
private let listIdentifier = "listIdentifier"
var taskArr: [taskList] = []
let defauls = UserDefaults.standard
class ViewController: UIViewController {
#IBOutlet var tableView:UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Tasks List"
tableView.delegate = self
tableView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
}
#IBAction func newTaskButton_Tapped(_ sender: Any){
self.performSegue(withIdentifier: "newTaskSague", sender: nil)
}
}
extension ViewController: UITableViewDelegate{
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
extension ViewController:UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {return taskArr.count}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: listIdentifier, for: indexPath) as! listCell
let row = indexPath.row
let formatter = DateFormatter()
cell.title?.text = taskArr[row].name
formatter.dateStyle = .medium
formatter.timeStyle = .short
cell.subTitle?.text = "Due: \(formatter.string(from: taskArr[row].dueDate))"
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete{
taskArr.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
}
With user defaults you can pretty much whatever you need but mind that is an internal database to small stuff as checking a boolean, an integer minimal data that you need as extra logic not as storage place, i you are planning to save a lot of entries of your Task model, you should consider to user CoreData.
What I suggest, is save an array of tasks in your UserDefaults (again if is not so much) and when you come from background, you need to check if your UserDefaults is empty, something like
override func viewDidLoad() {
super.viewDidLoad()
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(appMovedToForeground), name: Notification.Name.UIApplicationWillEnterForeground, object: nil)
}
func appMovedToForeground() {
print("come from background")
}
For objects array you will need to use archiver, you will need to add to that method of appMoveToForeground something like:
guard let dataTasks = UserDefaults.standard.object(forKey: "task") as? Data else { return nil }
if let tasks = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [Task.self], from: dataTasks){
if tasks.isNotEmpty() {
}
}
}
i still didnot get it how to implment this in my code .and im not trying to save big size of data just couple of them i dont need to use coreData

My custom cells are not showing up in my tableview

So I have been trying to get my custom cells to show up on this tableview, but I am not sure as to why they are not showing up
I have already checked other stack overflow questions and tried their fixes, to no avail. Please ignore the aws stuff as you can see I have the text hard coded so I can just get them to appear for now.
This is the code within the class holding the tableview
import Foundation
import AWSDynamoDB
import AWSCognitoIdentityProvider
import UIKit
// this will be the main feed class showing the user data
class UserDetailTableViewController : UITableViewController {
// attributes for the custome cell
#IBOutlet weak var testing: UITextField!
#IBOutlet var Table: UITableView!
var response: AWSCognitoIdentityUserGetDetailsResponse?
var user: AWSCognitoIdentityUser?
var pool: AWSCognitoIdentityUserPool?
var questiondata : Array<Phototext> = Array()
override func viewDidLoad() {
tableView.delegate = self
tableView.dataSource = self
super.viewDidLoad()
self.pool = AWSCognitoIdentityUserPool(forKey: AWSCognitoUserPoolsSignInProviderKey)
if (self.user == nil) {
self.user = self.pool?.currentUser()
}
// grabbing data from our aws table
updateData()
self.refresh()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.setToolbarHidden(true, animated: true)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.setToolbarHidden(false, animated: true)
}
#IBAction func Questions(_ sender: Any) {
performSegue(withIdentifier: "ask", sender: self)
}
// MARK: - IBActions
#IBAction func signOut(_ sender: AnyObject) {
self.user?.signOut()
self.title = nil
self.response = nil
self.refresh()
}
// reloads the prior view
func refresh() {
self.user?.getDetails().continueOnSuccessWith { (task) ->
AnyObject? in
DispatchQueue.main.async(execute: {
self.response = task.result
self.title = self.user?.username
// saving the user name from the main menu
username123 = self.user?.username! ?? "broken"
})
return nil
}
}
// function that calls to our aws dynamodb to grab data from the
// user
//and re update questions
// the array list
func updateData(){
let scanExpression = AWSDynamoDBScanExpression()
scanExpression.limit = 20
// testing to grabt the table data upon startup
let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.default()
dynamoDBObjectMapper.scan(Phototext.self, expression:
scanExpression).continueWith(block: {
(task:AWSTask<AWSDynamoDBPaginatedOutput>!) -> Any? in
if let error = task.error as NSError? {
print("The request failed. Error: \(error)")
} else if let paginatedOutput = task.result {
// passes down an array of object
for Photo in paginatedOutput.items as! [Phototext] {
// loading in the arraylist of objects
// adding the objects to an arraylist
self.questiondata.append(Photo)
}
DispatchQueue.main.async {
//code for updating the UI
}
}
return ()
})
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// returning the number of rows
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath:
IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:
"Questionpost", for: indexPath) as! QuestionCell
cell.QuestionText.text = "call it"
cell.Subject.text = "a day"
return cell
}
}
}
Here is the code for the QuestionCell class
import UIKit
class QuestionCell: UITableViewCell {
#IBOutlet weak var Subject: UILabel!
#IBOutlet weak var QuestionText: UITextView!
}
The cell class is called QuestionCell and the identifier I left on the cell in the storyboard is Questionpost
Here is a photo of my story board:
I have fixed it by declaring an extension with the proper types.
extension UserDetailTableViewController: UITableViewDataSource,UITableViewDelegate{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// returning the number of rows
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Questionpost", for: indexPath) as! QuestionCell
cell.QuestionText.text = "call it"
cell.Subject.text = "a day"
return cell
}}
good explanation of what's going on, you need to conform to the UITableViewDataSource and UITableViewDelegate when you inbed a tableview.
Redundant conformance of TableView to protocol UITableViewDataSource with Xib Files

How to pass data in tableview using swift 3?

I want to get, store & pass an URL in tableview to another table view in swift 3?
I am trying a lot but i can't do it? Please help me.
class EpisodesTableViewController: UITableViewController
{
var episodes = Episode
var audioPlayer : AVAudioPlayer!
var selectedVideoIndex: Int!
override func viewDidLoad()
{
super.viewDidLoad()
episodes = Episode.downloadAllEpisodes()
self.tableView.reloadData()
tableView.estimatedRowHeight = tableView.rowHeight
tableView.rowHeight = UITableViewAutomaticDimension
tableView.separatorStyle = .none
}
override var preferredStatusBarStyle : UIStatusBarStyle {
return .lightContent
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return episodes.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Episode Cell", for: indexPath) as! EpisodeTableViewCell
let episode = episodes[indexPath.row]
cell.episode = episode
return cell
}
// MARK: - UITableViewDelegate
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath:
IndexPath)
{
tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "secondView", sender: indexPath.row)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var next = segue.PViewController as! PlayTableViewController
next.index = sender as? Int
}
here is the another code
class PlayTableViewController: UITableViewController
{
var play = [PlayView]()
var audioPlayer : AVAudioPlayer!
var indexOfCell:Int?
override func viewDidLoad() {
super.viewDidLoad()
super.viewDidLoad()
play = PlayView.downloadAllEpisodes()
self.tableView.reloadData()
tableView.estimatedRowHeight = tableView.rowHeight
tableView.rowHeight = UITableViewAutomaticDimension
tableView.separatorStyle = .none
}
override var preferredStatusBarStyle : UIStatusBarStyle {
return .lightContent
}
override func numberOfSections(in tableView: UITableView) -> Int
{
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return play.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = tableView.dequeueReusableCell(withIdentifier: "Player Cell", for: indexPath) as! PlayerTableViewCell
let playV = play[indexPath.row]
cell.PV = playV
return cell
}
// MARK: - UITableViewDelegate
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath:
IndexPath)
{
tableView.deselectRow(at: indexPath, animated: true)
let episode = play[indexPath.row]
let player = AVPlayer(url: episode.url!)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
}
}
class PlayView {
var name: String?
var thumbnailURL: URL?
var url: URL?
init(name: String, thumbnailURL: URL, url: URL)
{
self.name = name
self.thumbnailURL = thumbnailURL
self.url = url
}
init(pvDictionary: [String : Any]) {
self.name = pvDictionary["name"] as? String
// url, createdAt, author, thumbnailURL
url = URL(string: pvDictionary["alt_url"] as! String)
thumbnailURL = URL(string: pvDictionary["alt_image"] as! String)
}
static func downloadAllEpisodes() -> [PlayView]
{
var playView = [PlayView]()
let url2 = URL(string: "http://nix2.iotabdapps.com/apk/items.json")
let jsonData = try? Data(contentsOf: url2!)
if let jsonDictionary = NetworkService.parseJSONFromData(jsonData) {
let pvDictionaries = jsonDictionary["items"] as! [[String : Any]]
for pvDictionary in pvDictionaries {
let newPlayView = PlayView(pvDictionary: pvDictionary)
playView.append(newPlayView)
}
}
return playView
}
}
I want to get the URL from tableview when user clicked.
I want to get an URL when click the Tableview then save it and pass it to the another tableview.
I can do this in JAVA but i am failed to convert in SWIFT 3
here is my java Example
itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
resultp = data.get(position);
Intent intent = new Intent(context, FragmentDemoActivity.class);
intent.putExtra("videoId", resultp.get(Main.VIDEO_ID));
context.startActivity(intent);
// Get the position
}
});
return itemView;
Can anyone help me please?
You need to implement prepareForSegue method
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath:
IndexPath)
{
tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "secondView", sender: indexPath.row)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var next = segue.destinationViewController as! PlayTableViewController
next.indexOfCell = sender as? Int
}
//
class PlayTableViewController:UITableViewController
{
var indexOfCell:Int?
}

Resources