I've just updated Xxode to work with Swift 2.0. As usual, a lot of new problems showed up.
In my app I have a view controller that checks whether the user is logged in and present either login screen or the app's home screen. It's a pretty simple VC:
class WelcomeViewController : UIViewController {
override func viewDidAppear(animated: Bool) {
if PFUser.currentUser() == nil {
self.performSegueWithIdentifier("segue-require-login", sender: self)
}
else {
self.performSegueWithIdentifier("segue-start-app", sender:self);
}
}
}
That used to work perfectly, but now it doesn't. The segue segue-require-login is of type "Present modally" and it works fine. The segue segue-start-app is "Show (e.g. Push)", but the view never gets pushed, even though the code is being executed (even prepareForSegue is called).
I've tried re-creating the segue, performing a Clean, cleaning the project's build folder but nothing seems to help.
Any thoughts?
There seems to be a bug in iOS 9 and Xcode 7 where if you have a UITextView with placeholder text, it prevents the segue from being triggered.
More explanation in the following answer:
iOS 9 Segue Causes App To Freeze (no crash or error thrown)
To fix it, try removing the placeholder text for the UITextView
I think I have the same problem: I have a UITabelView with cells created from a nib file, when a user tap a cell this method is called:
and when I have the following method prepareForSegue:: the application crashes:
if I delete the line 129 Everything is ok , the method prepareForSegue:: open the right view and the label contactName is shown with its default text.
If I modify the method as follows prepareForSegue:: get exactly what you expect, without having any type of error:
let me know if you also get the same result
Related
I am trying to implement a segue programmatically in IOS.
My story board looks like this:
The first segue between the first two screens is done by connecting the Login button to the next screen (so not completely programmatically), and it works fine.
The issue is with the "secondSegue", which I tried doing programmatically.
It simply does not work and there is no error message appearing.
I connected the 'Load this Screen' button to the following action in the Second Screen's view controller:
#IBAction func openThirdScreen(_ sender: Any) {
performSegue(withIdentifier: "secondSegue", sender: nil)
}
But the screen isn't opening and there is no error.
All the proper IBOutlets seem connected so I don't know what the issue could be.
I put a print statement in openThirdScreen(), and it prints, but a print statement in the third screen's View Controller's viewDidLoad() does not print, even though
I made sure the third screen was connected to a view controller.
I had overridden performSegue() earlier in order to do more with the segue but it was not working so I removed it for simplicity.
Please let me know what I messed up.
Sorry if this is a stupid question, I'm very new to XCode and I couldn't find anyone online with the same issue.
Let me know if there are more screenshots that are necessary to answer my question.
Edit: the following image was requested, in order to answer the question
Now I created a new project to test unwind segue.
In Storyboard the story entry is on VC0, a button in VC0 goes to VC1 (modally), a button in VC1 goes to VC2 (modally).
VC2 has a button to dismiss itself and in the function it looks like this:
#IBAction func btnDismiss(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
in VC1 I added an unwind function as follows:
#IBAction func unwindSecondView(segue: UIStoryboardSegue){
print("unwinded")
}
Then in storyboard I linked VC2's exit icon to unwindSecondview as action.
It works pretty well, however after I clicked "dismiss" button in VC2, VC1 appeared briefly and jumped back to VC0.
??? Anything wrong that caused jumping back to VC0?
--------------Initial question -----------------
I'm new to iOS and got a little confused for how VCs are created and activated.
Say I created 2 ViewControllers in my single view app. MainController(VC_M) and SettingsController(VC_S). I added the segues in storyboard, a setting button in VC_M goes to VC_S, VCS collects information, writes to standardDefaults, then ok button goes back to VC_M and refresh its view.
When I try to preserve some information in VC_M, I found that after I click ok button in VC_S and go back to VC_M, VC_M gets recreated and viewDidLoad() gets called. In the debugger, it shows the VC_M object (self) now has a different address in memory, so seems it's another instance of the class.
Is this a normal behavior? It's best that the old VC_M object gets saved so some data doesn't need to be reloaded. Initially I thought I could put some data loading stuff in init(), but when VC_M gets re-created init() got called, too. Some older posts suggested that ViewDidLoad() should not be called again but rather ViewDidAppear() should get called, but I'm not sure if it's the same case now.
In my case is it better to just use standardDefaults to reload everything, or is there a different kind of segue I should use? (I used push segue).
I am struggling with this problem for a few hours now.
I have a view with a tableView and custom cell in it. What I am trying to do is to perform a segue which is in my viewController from the custom cell. The first thing I did was to create a variable called "parent" in my cell.swift with the type "viewController".
weak var parent : ViewController!
After that, I'm just trying to perform the segue like this :
parent.performSegueWithIdentifier("eventDetails", sender: parent)
And I have the following error : Receiver (<Deevent.ViewController: 0x7fb99074f5d0>) has no segue with identifier 'eventDetails'
So I tried something else... I created a button in my ViewController and connected a segue to the next view (everything from the storyboard file)
In my viewController.swift I created the following function
func viewEventDetails() {
performSegueWithIdentifier("eventDetails", sender: self)
}
and this one in my cell.swift :
func viewEvent(sender: AnyObject) {
parent.viewEventDetails()
}
So when I call it from the cell, it crashes with the same error than before but when I click on the button it's working. I even tried to click on the button programmatically btnDetails.sendActionsForControlEvents(UIControlEvents.TouchUpInside) and I had the exact same error.
I've already tried to clean my project and delete it from the simulator. I'm really missing something here... hope somebody can help me.
Thanks !
It sounds like you need to give your segue an Identifier.
A view controller can have multiple segues, and so you need to define which one you want to use. In your case, in your code you are using the Identifier "eventDetails".
Assuming you are using a Storyboard, you need to click on the segue arrow between the two view controllers, and in the Attributes Inspector on the right, set the Identifier value to "eventDetails".
I upgraded my Swift app to Xcode 7 / Swift 2.0 and now suddenly certain segues in my app no longer work.
I have a segue popping up a "Check In" modal and it works perfectly, but then I have another segue popping up a "Check Out" modal that's near identical and it doesn't launch and the app is frozen.
I re-created the segue from scratch, confirmed that it is identical to the "Check In" one, and it still doesn't work.
I also, instead, tried launching a blank view instead of my Check Out modal and it works fine.
There are no errors, it just freezes, I did confirm that the "prepareForSegue" portion is being called correctly but the "viewDidLoad" portion of my modal is not being invoked.
FYI, I have auto-layout turned off.
Does your "Check Out" modal have a UITextView? If it does, then there's a bug in Xcode 7 / iOS9 where you cannot launch a modal (or any root view) that contains a UITextView if you have set a default text value in storyboard.
A work around is to make sure your UITextView in storyboard is either blank or has the default Lorem Ipsem value and instead, set the text programmatically in code on viewDidLoad.
Hopefully this bug will be fixed soon.
I suspect there is infinite loop somewhere in you "Check Out" controller code. Try pausing app in debugger after presenting controller (when it freezes) and check stacktrace. If it doesn't help, try commenting-out code line-by-line in viewDidLoad and viewWillAppear to find line causing freeze.
I had this problem, try with this
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("Storyboard Id")
self.presentViewController(viewController, animated: true, completion: nil)
})
You just have to give a storyboard id in your view and normally it's working.
My app was working perfectly in iOS8. Its flow was:
VC: View Controller, NVC: Navigation View Controller, ER: Embedded root relationship between NVC and VC, PS: Push Segue, PG: Programmatic presentation
NVC1---(ER)->VC1---(PS)->NVC2---(ER)->VC2 and so on.
The problem was that VC1-(PS)->NVC2 segue did not work, there was no freeze. vc1.prepareForSegue() was executed, but VC2 was not presented. I experimented and found that I did not have the UITextView problem mentioned here.
By following the breadcrumbs outlined below, I got it work after hours of trying in the following way (code at the end):
NVC1---(ER)->VC1---(PG)->VC2
Here are the steps:
As mentioned in Segue issue in iOS9, multiple NVCs are out of style (shame on Apple for suddenly ditching what is actually recommended in your online tutorial and making apps break!). So I modified
NVC1---(ER)->VC1--(PS)->VC2 while VC2 was still embedded in NVC2. I got errors
similar to the StackOverflow post on view not in hierarchy. So I started doing the transition programmatically and after tackling present vs. push ViewController issue that results in "tried to push modally on active view controller" message and then ViewController lifecycle issues that result in "Unbalanced calls to begin/end appearance transactions" messages, I got the following code working. Based on this experience, I really think Apple should have left a working thing alone in Xcode7/iOS9 update.
//*********** VC1.swift. A translation of working code
class VC1:UIViewController{
private var viewController2:VC2?
private var showVC2: Bool = false
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if(showVC2) {
showVC2 = false
self.pushVC2()
}
}//viewWillAppear
private var info:String? // info from incoming user action.
#IBAction unwindToVC1FromUserAction(incomingSegue: UIStoryboardSegue?) {
// Do app-specific stuff to get info from incomingSegue and
// store in self.info variables.
let myboard: UIStoryBoard = self.storyboard!;
self.viewController2 = myboard.instantiateViewControllerWithIdentifier(
"VC2 Storyboard ID") as! VC2
self.prepareVC2() // Pass info to VC2.info, stuff you would have done in prepareForSegue
showVC2= true
} //unwind
private func prepareVC2() {
self.viewController2.info = self.info // etc..
}
private func pushVC2() {
self.navigationController!.pushViewController(viewController2!, animated:false)
}
} //class
I had this, but it was none of the above. My segue call happened to be inside a block. When I moved the call to the main thread I saw that I had a 'NSUnknownKeyException' error in the new View Controller. Being inside the block seemed to prevent the error from registering in Xcode, so the app just appeared to hang without any errors.
Once that was resolved the original code worked fine.
I'm struggling to change to a UI View Controller as a game over screen, on this screen I plan on showing the score, reset and advert. I'll show you my code that I have already then below I'll list how my project is set up.
The game runs however once contact is detected the crash states
Thread 1 EXC_BAD_INSTRUCTION (code=EXC1386_INVOP,subcode=0x0)
Here is the code I've used so far...
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var viewController: GameViewController!
var secondViewController: GameOverViewController!
override func didMoveToView(view: SKView) {
//lots of code here
func didBeginContact(contact: SKPhysicsContact) {
if( moving.speed > 0 ) {
moving.speed = 0;
self.viewController.performSegueWithIdentifier("GameOverViewController", sender: self)
}
I currently have the below set up:
My two view controller files GameViewController.swift & GameOverViewController.swift
In addition to my current GameViewController view I have a new view controller on my storyboard with the following attributes.... Class:GameOverViewController & Storyboard ID:GameOVerViewController
A triggered segue is set up (push) from GameViewController to GameOverViewController
A then have the following code in my GameScene.Swift file
If anyone could help me that would be great.
Thank you.
performSegue:withIdentifier: should work unless you have not setup the the storyboard correctly.
What error do you get on doing performSegue:withIdentifier: ?
Did you setup a segue in storyboard connecting the two view controllers and does that segue have an identifier called secondViewcontroller?
Take a look at this Storyboard tutorial.
Maybe you are trying to push a view controller without a navigation stack, if that's your case, try presenting modally your view controller, check as well how do you have wired the segue. Sorry for my bad english.
Change your performSegue call to
self.viewController.performSegueWithIdentifier("DOES_NOT_EXIST", sender: self)
And re-test. Do you get the same error? If so, you haven't named your segue properly. The segue name set in the Interface Builder must exactly match the segue name you try to call in your code. To fix this: Select the segue in the interface builder, Read the Identifier box to the correct name, update your performSegue call to use exactly that string and rebuild. (if you update the identifier in the Interface builder, make sure you clean the project before rebuilding to ensure the new symbol is picked up).
If, however, the test results in a different error, "'Receiver <> has no segue with identifier 'DOES_NOT_EXIST'" then your original perform segue call was working fine. Put it back the way it was. Something else is causing your crash.