swift update textview after typing new text - swift

I'm making an app in swift 3
I have a TableViewController, when I click on a row it opens a ViewController in which there is a TextView. When I click on it, I am able to edit it, but the changes are not "saved". when I go back to my list and re-click on the same row, the text is back to "Default", I've been on this problem all day, and I don't know how to solve it, I've tried solution from stackoverflow but only give solution to change the text colours.
So how can I do that ?

Based on what you've said so far, I can only assume that you are not storing the new text that's been entered into your UITextView.
The reason that the changes are not being saved is that every time you "open" a new ViewController by tapping on a TableViewCell, it is a brand new instance of that ViewController. That means that it has no input as far as what should be displayed in the TextView, and therefore displays the default text.
But how do I fix it?
This is going to require that you save your TextView's text every time that you leave or dismiss the ViewController. This is because when you leave the ViewController, it is being released from memory. This means that anything that was written there no longer exists. I would suggest storing the text in an array of strings on your TableViewController, which should allow for the text to persist over the life cycle of the app.
The text disappears when I close the app!
This is something that will require data persistence, and for that I would suggest reading up on how to use Core Data to store and persist data across multiple app life cycles.

There are many ways to achieve that, the idea is to set the text of the text view in its view controller's initialization.
So, you need a place to save the data entered by the user, and then read that data again in the view controller's initialization.
One way to do that is using a singleton class to save the data, like this for example:
class SharedData {
static let instance = SharedData()
var textEnteredByUser: String?
}
Now, when the user enters text, save that text in the string we have in 'SharedData' like this:
SharedData.instance.textEnteredByUser = textView.text!
Now, we have the data entered by the user saved, we need to set the data in the text view before it appears in the screen, and this can be achieved inside viewDidLoad method of your view controller like this:
override func viewDidLoad() {
super.viewDidLoad()
textView.text = SharedData.instance.textEnteredByUser
}
You can also save your data in user defaults instead of the singleton class like this:
UserDefaults.standard.set(textView.text!, forKey: "textEnteredByUser")
And then retrieve the saved text this way:
UserDefaults.standard.string(forKey: "textEnteredByUser")
Note: The singleton solution keeps the data shared between different view controllers, but does not persist data after closing the application, and this is what user default does.

Related

How to update a value after it is loaded inViewDidLoad in another file (Swift)?

I have created all my views programatically and to the UIView I have created an extension. This extension is present in a different file called App+Extensions.swift
extension UIView {
func setupParentView() -> UIView {
//...
}
}
The setupParentView() gives me a view with my navbar and background colour. As the design is same everywhere I have used this function. This function is called everywhere in viewDidLoad. So, now in this function the navabar consists of points which need to updated every time the user has purchased/spent it.
So, now as this method is only called in viewDidLoad the function is not called again and the point value do not change in the navigation bar. So, how can I update the point value every time it is changed? I thought of using Combine, but this app will be available for iOS 12 users as well, and I am not using RxSwift, so any help?
Well ViewDidLoad won't get refreshed because your view is now in the stack hierarchy. Some override methods that do get called which have a relation to the view are viewWillAppear, viewDidDissapear, and viewDidAppear.
If your view is going back in forth and the point button needs to be updated everytime your view re-appears consider putting the "refresh" point number in one of the above methods.
Note if your sending info back and forth between two views its also best maybe implement a delegation pattern or an observer.
Use notifications.
In other words, have points be a property of a global object that lives off in "data space" as a singleton. Now just use a property observer so that whenever anyone changes that object's points property, it emits a notification through the NotificationCenter.
That way, any view or view controller that needs to update whenever the points property changes just has to register for that notification when it comes into existence.
[Basically, this is the mechanism, or one of the mechanisms, that you would be replacing or even using directly if you were using Combine or RxSwift.]
Create a custom view called NavBarView
This NavBarView has a property called point
var point = 0 { didSet { updateView() } }
You want to avoid singleton, single view object, so that not everything is coupled together.
You don't need RxSwift or notification to do this.

Get Text Input WITHOUT UITextField Swift

I'm making an app and I want the user to be able to input text without having them actually click on a UITextField (have it open after the game ends for a scoreboard), is there some way to do that?
Call the following in the viewDidLoad of scoreboard, or whatever the entry point of that view is.
yourTextField.becomeFirstResponder()
Yes, just:
<#your_text_field#>.becomeFirstResponder()
after the game ends.
This will produce the "same" effect as a tap on the UITextField. If this is on a new UIViewController you can place it on viewDidAppear, otherwise you can assume everything is already loaded and simply call it anywhere.

How to preload data before moving to another VC

I have a method that reads some data from a database and returns it in a closure, for example:
DatabaseManager.readUser(withUserID: "Bob") { (user, error)
MySingleton.shared.user = user
}
I have a home VC which is my landing page, and a "user" VC that a user can navigate to. My user VC needs to display the data read from the database, in this case MySingleton.shared.user.
My problem:
I am currently trying to load the user's data on a background thread in my home VC, so by the time the user navigates to the user VC, the data can be displayed. However, if the user navigates to the user VC too fast, before the data was read, my app crashes because MySingleton.shared.user is nil, as expected.
My other option would be to load the data in viewDidLoad() in my user VC and display it after it was set in the closure. But this might cause there to be a kind of blank screen between the time the VC loads, and the time the data was read.
What is the best option here for a seamless user experience? Is there a way I can try to preload it in my home VC, and if its still not set by the time I navigate, wait until it is before displaying the user data?
If you want to start data loading when the screen is opened you can proceed in the following way:
On button tap check that you data is loaded. If yes - open the next screen, if no - set a flag (for instance openScreenOnDataLoad = true) and display a progress indicator.
In your closure when the data load is finished check that flag and open the next screen if the flag is set.
If you are initiating the data load in some other place/class you can use notification to inform other parts of the program that the data was loaded.
My general advice in these type of cases:
When Moving to a new ViewController, any required dependancies should be injected at the time of initialization/segue, and everything else should be handled internally during the ViewController's life cycle.
This makes the requirements for showing the ViewController clear, minimizes state complexity, and increases modularity.
In your case that means either the HomeVC needs to load the date (preferably indicating loading somewhere in the UI) and send it to the UserVC when it's made, or the UserVC will need to load the data and handle any loading UI there.
Personally I would prefer the second option minimize dependencies, simplifying navigating from anywhere else.
As an aside, if you're sure you want to use a singleton like that it's generally a good idea to handle the singleton management (creation, destruction) in the Model, and (at most) only access it from your ViewControllers

Dynamically Updating A Tab Bar Item In the More ViewController Table

OK. I haven't actually seen how to do this anywhere. It may be a question of "You can't get there from here." or "Holy ##$! That is such a disgusting hack it should be taken behind the woodshed and shot!".
I have a tabbed Swift 3 iOS app that will dynamically update the Tab Bar images of selected pages as the page state changes.
I do that sort of like this:
if let navController = self.navigationController as? MyNavController {
navController.tabBarItem.image = navController.tabBarImage
navController.tabBarItem.selectedImage = navController.tabBarImage
}
The tabBarImage is actually a calculated property. This snippet is called within a UI callback that updates when the state changes.
This works great.
When in the MoreViewController, though, not so great. Those images remain stubbornly static, no matter what I do.
I have done some exploration of the MoreViewController. I can get at the tableView and the cells, but that smells like the kind of hack that will get my app taken behind the woodshed by the Blue Meanies at App Review.
Is there a proper way to do this?
You can use Notification and pass the images within a Dictionary as a Notification object. Then you can get different tabBarImage with different key value at once.
OK. I figured out how to do it.
I was crawling back along the navigation controller path; which worked fine for items not in the more space.
I fixed it by crawling forward from the tab bar controller, instead:
self.tabBarController?.viewControllers?[MySelectionIndex].tabBarItem.image = self.tabBarImage
self.tabBarController?.viewControllers?[MySelectionIndex].tabBarItem.selectedImage = self.tabBarImage

Keeping data in a UIViewController, even after go to a TablevViewController and come back?

I have a UIViewController with some UITextFields in it which holds username and other details. And i need to go to another view, which is a UITableView which holds the list of countries to user to choose and get back to the UIViewController again, when user picks one.
What my problem is i will lose all my data mentioned previously in the UIViewControl, when get back from UITableView. I can use application's delegate to store data when go to UITableView and load them back when UIViewController is loaded again.
I was wondering, whether is there a way to achieve my goal, other than this approach? I have to use number of variables in the delegate to store these data as there are many.
Can anyone help me out with an idea please???
I dont think.But I think you are reloading the table in viewWillAppear.Thats why ur older values are not remaining