reload after a unwind to viewController in swift 3 - xcode

I have put in TableViewControler (my third page) a table to select a variable and next unwind to a ViewController and reload it with the new value but I tried to search about but I didn't found the answer. I'm working with swift 3 please help me

Unfortunately swift doesn't have a method to reload a view after it's already loaded. When you push your TableView, the former ViewController remains loaded in the background.
you can add the following code to any ViewController to see when it load and when it deallocate.
required init?(coder aDecoder: NSCoder) {
print("init controller")
super.init(coder: aDecoder)
}
deinit {
print("deinit controller")
}
Now I don't know how your code works in the ViewController but im guessing you're using viewDidLoad() to set it up in the first place. In that case you can try including the code you use to setup the ViewController in func viewWillAppear(_ animated: Bool) to reload the view when it reappears.
If you can provide your code I might be able to provide you with a better answer.

Related

The first time a TableView row is selected, it does not respond

I wrote a simple app with two view controllers:
TableViewController with a table of websites to select
ViewController with a WKWebView that loads the website. This ViewController also has a key-value observer that refuses to load websites not in an approvedWebsites array that is filled from the TableViewController upon selecting a website.
Here's the most relevant code, can add more as requested. This is the didSelectRowAt function in TableViewController:
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let vc = storyboard?.instantiateViewController(withIdentifier: "Browser") as? ViewController {
vc.approvedWebsites = websites
vc.selectedWebsite = websites[indexPath.row]
navigationController?.pushViewController(vc, animated: true)
}
Currently, when I run the program and select any row, that row will remain highlighted and not respond. I added a print function to the row (above the if let) and it will not print.
However, the next row I select will respond, but with the website from the row I previously selected. I've tested this vigorously and it always will load the website of what I selected previous. When I back out of the webView screen, it'll reset everything and I can recreate the same error without reloading the app.
Any ideas as to what's happening?
Figured it out. Make sure you used DidSelectRowAt not DidDeselectRowAt.

performSegueWithIdentifier causes fatal error: unexpectedly found nil while unwrapping an Optional value

What I need was to detect which cell was selected on my tableView, and using the indexPath.row to get the index of my object array which is personList, and pass that data to another View Controller and print on the label.
However, I received an error fatal error: unexpectedly found nil while unwrapping an Optional value
Below are my codes.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
selectedCell = indexPath.row
performSegueWithIdentifier("DetailScreen", sender: nil)
}
override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) {
//detailedView.personName = personList[selectedCell].GetPersonName()
detailedView.LastNameLabel.text = personList[selectedCell].GetLastName()
}
The problem is that you initialize the detailedView in the wrong way. Do it like this:
// IMPORTANT: Override prepareForSegue for your purpose, not performSegueWithIdentifier
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DetailScreen" {
// Do the initialization here. You don't need a global variable.
if let detailedView = segue.destinationViewController as? PersonDetailScreen {
//detailedView.personName = personList[selectedCell].GetPersonName()
detailedView.LastNameLabel.text = personList[selectedCell].GetLastName()
}
}
}
PS: You are overriding the wrong function.
EDIT
As mentioned in your comment didSelectRowAtIndexPath and prepareForSegue doesn't coexist because the method you used for creating the segue is wrong. And with that, your code is doing more wrong than doing the right thing. Right now you might have created the segue by control dragging starting from the UITableView prototype cell to the destination view controller. Now when you do this what happens is, you are telling that the segue must be performed on the clicking on that particular cell itself, which means you are setting its action right in the storyboard. So even if you don't implement didSelectRowAtIndexPath, your code will still navigate to the second ViewController when the cell is clicked. But your requirement is that you must do some custom operations when the cell is clicked and then navigate to the second viewcontroller. For doing that, delete the current segue and then create a new segue with the same identifier like the way you create a normal segue - by control dragging from the source ViewContoller(not the tableview cell prototype) to the destination view controller. Then replace the override func performSegueWithIdentifier(identifier: String, sender: AnyObject?) function with the function I have provided in my original answer and then your code will work smooth.
PS: Make sure your Identifier is named correctly.
'NSInvalidArgumentException', reason: 'Receiver (<PersonDisplay.FirstViewController: 0x7feabaec2870>) has no segue with identifier 'DetailScreen''
This happens since you haven't set the name for the segue correctly in the storyboard. So rectify that as well. Specify the identifier for the segue in the storyboard.
You should pass valuable to detailedView and assign to label in viewDidLoad:
detailedView.lastName = personList[selectedCell].GetLastName()
Go viewDidload of detailedView:
detailedView.LastNameLabel.text = detailedView.lastName

OS X addsubview from xib in swift

I'm trying to add a new sub view form a nib using swift for OS X.
So far i've:
created a new "Cocoa Application"
added a new "Cocoa Class" called "TestSubView" as a subclass of NSViewController with a XIB file
I want to add this subview to my main view when the application loads.
in my ViewController ( the ViewController for the main window ) i have.
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let newSubView = TestSubView();
self.view.addSubview(newSubView.view);
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
But i'm getting the following error
Failed to set (contentViewController) user defined inspected property on (NSWindow):
-[NSNib initWithNibNamed:bundle:] could not load the nibName: temp.TestSubView in bundle (null).
I realise i will need to size and position this subview but I can't seem to get to that point.
I've spent the better part of a day trying to figure this one out so any help would be greatly appreciated.
I finally got this thing to work. My new code looks like
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let subview = TestSubView(nibName: "TestSubView", bundle: nil)!
self.view.addSubview(subview.view)
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
Found with the help of the docs & this answer
It was suggested that if the nib name and the class name are the same you shouldn't need to declare nibname: (as i'd tried to do originally) but the docs didn't mention this - explains why it didn't work!
For prosperity, this worked for me with Xcode 6.1.1 on OS X Yosemite (10.10.1)
A nib is really nothing but an XML file with view information in it. You have to get it from the application bundle and get one of the views contained in it explicitly. You are perhaps confounding views and view controllers (your attempt to extract view from newSubView suggests that).
Try this:
let subview = NSBundle.mainBundle().loadNibNamed("TestSubView",
owner:self, options:nil)![0]! // maybe no final unwrapping "!" in Swift 3
self.view.addSubview(subview)
Make sure the xib is really called the name you are using and contains at a least one view (otherwise the two unwrapping ! above will crash your app).

Can't figure how to to hook up a UIView class to a View in IB using Swift

** Updated **
I'm working on an idea in Swift and can't seem to figure out how to get a view hooked up to a view class.
I have a UIViewController in IB and a UIViewController class that is associated to that UIViewController in IB. Inside the UIViewController and drug in UIView in IB. I want to give that UIView it's own class. I have a Text Field inside of the View and I would like the UIView class to handle all of the setup code for that text field. I able to create the UIView class, but and I was also able to set it as the bast class for the View in IB. What I'm not 100% sure is how to Init this class so that I can create vars in the UIView class and control drag them to my Text Field in IB,
* Updated * This is my code so far.. it seems to be at least doing something but I'm getting the fetal error print message
import UIKit
class AddPlayerView: UIView
#IBOutlet weak var inputPlayerOne: UITextField!
#IBOutlet weak var addPlayerOne: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
// Initialization code
println("init add player")
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
This I get this printed out
fatal error: init(coder:) has not been implemented:
I just don't get your question. Initializing the view withing IB will fire the init(coder aDecoder: NSCoder) rather then init(frame: CGRect) and this is standard. Now if your concern is to access some variables not intialized then just override the func awakeFromNib(). And implement the required initializer just with the super
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override awakeFromNib(){
// Initialization code
}
Does this make sense?
You can create an Outlet following these steps (tested with Xcode6-Beta6 + Swift):
In Xcode activate the Assistant editor (you should have Storyboard on the left side of the screen and the Swift code on the right)
On the left select the a View (now on the right you should have the Swift Controller related to that view)
On the left perform a right click on a UI element (e.g. a UIButton in your view)
A dark transparent panel will appear over the UI element
Left click on the "circle/plus" button near the item New Referencing Outlet
Keep holding the left click and drag a line to the Swift Controller (e.g. where you would declare an instance property).
Release the left click
Xcode will ask you to give a name to the Outlet, type something like "button"
Click Connect
Done. Now in your swift class you have a reference to your UIButton.
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
...
Hope this helps.
Storyboard uses it's own initializer: init(coder:) to initialize its xibs. This also means that if you override one initializer, you must override the storyboard's required initializer as well (the coder one previously mentioned). It appears as if you did this, however for some reason you have put fatalError("init(coder:) has not been implemented") as your code in required init(coder aDecoder: NSCoder). This means that every time your views are initialized, that method is being called, and of course its going to throw a fatal error and crash your app. We must replace that code. Be sure to call super.init(coder: aDecoder) at the beginning of the method, and then place the rest of your initializer code afterwards. You might also find this Stack Overflow answer useful: Fatal error: use of unimplemented initializer 'init(coder:)' for class Please let me know if you have any more problems. Good luck!

What is a StoryBoard ID and how can I use this?

I am new to IOS developing and recently started in Xcode 4.5. I saw for every viewController that i could set some identity variables including the storyboard ID. What is this, and how can I use it?
I started searching on stackoverflow and couldn't find any explanation for it.
I assumed it's not just some stupid label that I can set to remember my controller right? What does it do?
The storyboard ID is a String field that you can use to create a new ViewController based on that storyboard ViewController. An example use would be from any ViewController:
//Maybe make a button that when clicked calls this method
- (IBAction)buttonPressed:(id)sender
{
MyCustomViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"MyViewController"];
[self presentViewController:vc animated:YES completion:nil];
}
This will create a MyCustomViewController based on the storyboard ViewController you named "MyViewController" and present it above your current View Controller
And if you are in your app delegate you could use
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
Edit: Swift
#IBAction func buttonPressed(sender: AnyObject) {
let vc = storyboard?.instantiateViewControllerWithIdentifier("MyViewController") as MyCustomViewController
presentViewController(vc, animated: true, completion: nil)
}
Edit for Swift >= 3:
#IBAction func buttonPressed(sender: Any) {
let vc = storyboard?.instantiateViewController(withIdentifier: "MyViewController") as! ViewController
present(vc, animated: true, completion: nil)
}
and
let storyboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
To add to Eric's answer and update it for Xcode 8 and Swift 3:
A storyboard ID does exactly what the name implies: it identifies. Just that it identifies a view controller in a storyboard file. It is how the storyboard knows which view controller is which.
Now, don't be confused by the name. A storyboard ID doesn't identify a 'storyboard'. A storyboard, according to Apple's documentation, 'represents the view controllers for all or part of your app’s user interface.' So, when you have something like the picture below, you have a storyboard called Main.storyboard which has two view controllers, each of which could be given a storyboard ID (their ID in the storyboard).
You can use a view controller's storyboard ID to instantiate and return that view controller. You can then go ahead to manipulate and present it however you want. To use Eric's example, say you want to present a view controller with identifier 'MyViewController' when a button is pressed, you would do it this way:
#IBAction func buttonPressed(sender: Any) {
// Here is where we create an instance of our view controller. instantiateViewController(withIdentifier:) will create an instance of the view controller every time it is called. That means you could create another instance when another button is pressed, for example.
let vc = storyboard?.instantiateViewController(withIdentifier: "MyViewController") as! ViewController
present(vc, animated: true, completion: nil)
}
Please take note of changes in syntax.

Resources