Weird Error when setting detailItem in DetailViewController from MasterViewController - ios

I started getting this error randomly (may be due to updating swift) but when I reach, didSet in detailItem, I call configureView. In configureView I check to see if detailItem is indeed set and then start assigning values to my outlets.
if let detail: Posting = self.detailItem {
print("detail title is ")
println(detail.title)
// Title
self.titleLabel.text = detail.title
However this crashes with output:
detail title is Skiing in Vail
fatal error: unexpectedly found nil while unwrapping an Optional value
The error is on the line:
self.titleLabel.text = detail.title
I don't understand why it is crashing when it is is clearly set...
Note that this doesn't happen if I call configureView from within viewDidLoad.
This only happens when I call it from
var detailItem: Posting? {
didSet { self.configureView() }
}
Something I'm missing? Is this working asynchronously or something?

Referencing your comment on how to implement this, there are a few trains of thought. First, the reason you can modify it directly from your MasterVC is because the IBOutlet hasn't been instantiated in the DetailVC and thus isn't available to be modified yet.
One option, which I'd probably follow, is to have a helper variable on your detail view where you can place the value. Then viewWillAppear() you can take whatever's in the variable and set it as the label's text. Here's a tutorial on it, but to answer your specific quesiton please jump to the prepareForSegue method in this tutorial. It gives a good rundown of the whole process:
http://www.codingexplorer.com/segue-swift-view-controllers/
Let me know if this doesn't solve your problem.

Related

Why are my variable or cast empty in my iOS app? [duplicate]

This question already has an answer here:
Why are my variables empty when I cast them in my iOS application?
(1 answer)
Closed 1 year ago.
I'm coding an app on Xcode for IOS and I'd like to send a variable to another ViewController that hasn't appeared yet. The problem is that when I make a variable of my future ViewController like this :
guard let EndConfiguration = self.storyboard?.instantiateViewController(withIdentifier: EndConfiguration) as? EndConfiguration else
{
fatalError("Impossible d'acceder correctement au cellules des alarmes")
}
And I'm trying to do this:
EndConfiguration.ModeleOutlet.text = Alarme.shared.Alarmes[indexPath.row].Modele
I get this error :
Fatal error: Unexpectedly found nil while implicitly unwrapping an
Optional value
I understood the Optionels but if I add a "?" after ModeleOutlet it will remove the error but the text remains unchanged in my other ViewController. I'm sure that the value I modify is full, don't worry.
I'm replicating my problem because someone close it because there was already a solution when there wasn't one at all.
Thank you in advance.
try this
guard let EndConfiguration = self.storyboard?.instantiateViewController(withIdentifier: EndConfiguration) as? EndConfiguration else
{
fatalError("Impossible d'acceder correctement au cellules des alarmes")
}
_ = EndConfiguration.view
EndConfiguration.ModeleOutlet.text = Alarme.shared.Alarmes[indexPath.row].Modele
I am making the assumption that type of ModeleOutlet is a Label or of another type that may contain a text variable.
If ModeleOutlet is indeed a label that is attached via storyboard, then I urge you to read up on the ViewController lifecycle. Here is a great article describing it : https://medium.com/good-morning-swift/ios-view-controller-life-cycle-2a0f02e74ff5
Now, to answer your question specifically, you'll likely want to create a separate variable within your view controller then set the text variable within the function, viewDidLoad.
class EndConfiguration: UIViewController {
public var sharedText: String?
#IBOutlet var ModeleOutlet: UILabel?
func viewDidLoad() {
super.viewDidLoad()
self.ModeleOutlet?.text = sharedText
}
}

IF Statement Incorrectly Evaluating to True when Using Optional Values in Swift

I have set up my view controllers so that they send a notification once their -viewDidLoad method is about to return. For example:
class MyViewController: UIViewController{
override func viewDidLoad() {
super.viewDidLoad()
//Do Stuff
var notificationCenter = NSNotificationCenter.defaultCenter();
notificationCenter.postNotificationName("AViewControllerDidLoadNotification", object: self);
}
}
My AppDelegate class is listening for this notification and implementing the method shown in this picture.
In case the picture isn't loading, the method takes the notification sent by the view controllers as it's only argument and then tests whether the UIViewController's title property has a non-nil value. If the title property is non-nil it logs the title.
However, as you can see in the debugger panel, the title property of the view controller is nil and the if statement is still evaluating to true.
I am admittedly new to optional values. But I have recreated this situation in a swift playground and the if statement evaluates to false. Any ideas?
You've gotten yourself into rather an odd situation with your very peculiar use of the expression notification.object?.title, because notification.object is not, of itself, a UIViewController. It is an AnyObject.
Now, an AnyObject has no known properties, so it has no title and your expression, it would seem, should not even compile. But, by a special dispensation coming from certain oddities of Objective-C, you are in fact allowed to ask about an AnyObject's properties anyway. But when you do, the result is itself an Optional, because no such property might exist.
Thus, you are actually testing, not the value of a view controller's title property, but whether this unknown object has a title property in the first place; and if in fact it does have a title property at all, the value of that title property is double-wrapped inside that Optional.
To see this clearly, just test this (silly) code:
let n = NSNotification(name: "Howdy", object: "Hi")
let t = n.object?.title
Look at what type t is. It is not a String?; it is a String??. That's your double-wrapped Optional. This means that it would be an Optional-wrapping-a-String in case this object turns out to have a title property, but just in case, that value has itself been wrapped in an Optional.
Thus, your test doesn't do what you want it to do. To do what you want to do, just speak much more plainly and simply. You need to cast the object to a UIViewController first, and then examine its title. Like this:
func aViewControllerDidLoad(notification:NSNotification) {
if let vc = notification.object as? UIViewController {
if vc.title != nil {
// ...
}
}
}

iOS: unexpectedly found nil while unwrapping an Optional value

Getting the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value
I am making a registration form application. The app allows users to create custom questions to be added to a form. At the moment I'm using a Singleton design pattern to pass the list of questions between the editing tab and the tab used to display the form.
My singleton class:
class Singleton {
static let sharedInstance = Singleton()
var questions: [Question] = []
}
In the editing form the user will press a button to update the form that people can then fill out. Here is that code and is also where I'm getting the error:
var mySingleton: Singleton!
#IBAction func updateForm(sender: AnyObject) {
for index in mySingleton.questions.count...questionsArray.count {
mySingleton.questions.append(questionsArray[index])
}
}
Thank you for your help.
This is where the error is occurring:
for index in mySingleton.questions.count...questionsArray.count {
mySingleton.questions.append(questionsArray[index])
}
The final index that is looped through is questionsArray.count. When you access questionsArray[questionsArray.count], you are outside the bounds of the array. This index should never be accessed.
Instead, change your loop to the following:
for index in mySingleton.questions.count..<questionsArray.count {
mySingleton.questions.append(questionsArray[index])
}
The only difference is that ... becomes ..<, in order to leave out the last index that is causing the error.
Edit: after looking back at the code, it seems likely that mySingleton was never set equal to anything. Before this code is executed, you could set mySingleton = Singleton.sharedInstance, or simply get rid of mySingleton and directly use Singleton.sharedInstance.

Swift: Why is IBAction crashing app when I seem to have a reference to variable in separate UITableViewController?

I have a custom UITableViewCell class named PinCell.swift which contains a reference to a UITableViewController and an IBAction that passes data from the cell to the UITableViewController. I have no errors and everything builds fine.
PinCell.swift (UITableViewCell):
var viewControllerB:UITableViewController!
#IBAction func titleButtonPressed(sender: AnyObject) {
var venueIDFromRequest = self.pin?["venue"]["id"].stringValue
println("venueIDFromRequest is: \(venueIDFromRequest)")
if venueIDFromRequest != nil {
let venueDetailRef = viewControllerB as! VenueDetailViewController
venueDetailRef.venueIDPassed = venueIDFromRequest!
}
if(self.delegate != nil){ //Just to be safe.
self.delegate.callSegueFromCell(venueIDFromRequest: venueIDFromRequest!)
}
}
VenueDetailViewController.swift (UITableViewController)
var venueIDPassed:String! = "asdklasdkas"
When I tap the button in my app, it crashes and the following is printed out to the console fatal error: unexpectedly found nil while unwrapping an Optional value which we have all seen before and I realize what this error means. My question is why is this happening when it seems to have a reference to the variable in the other view controller? Even when I println(venueIDFromRequest) I get the correct data. What am I doing wrong here and how can I assign venueIDFromRequest to self.viewControllerB.venueIDPassed ?
Here is a screenshot if it can help diagnose what is actually going on:

Delegate Error in Swift

I am trying to send a double value from a UIView (which is loaded from a XIB) to a ViewController using a delegate
Here is my protocol, it is just sending a double to the main ViewController on a button click.
protocol HoursWorkedDelegate{
func sendHoursWorked(hoursWorked: Double);
}
class HoursWorkedView: UIView{
var delegate: HoursWorkedDelegate?;
#IBAction func calculateHoursWorked(sender: AnyObject){
// Do some calculations for the hoursWorked value
// Give value
delegate!.sendHoursWorked(hoursWorked);
}
}
// This class now wants that Double value
class ViewController: UIViewController, HoursWorkedDelegate{
// Conform to protocol
func sendHoursWorked(hoursWorked: Double){
// Lets say we just want to assign this value to a textField
hoursWorkedTextField.text = NSString(format: "%.4f", hoursWorked);
}
}
The error message I get is Thread 1: EXC_BAD_INSTRUCTION(code = EXC_I386_INVOP, subcode=0x0)
Any help would be much appreciated, Thank You!
As a start, change the exclamation point in this snippet to a question mark:
delegate!.sendHoursWorked(hoursWorked);
This is what's likely causing the crash, as you are force-unwrapping the optional delegate property. A question mark means we'll only call sendHoursWorked() on the delegate if the delegate exists.
That fix will now probably mean that your program is no longer crashing, but you still don't get the desired results, because sendHoursWorked() is never called. We have to tell our HoursWorkedView object who is delegating it.
Somewhere in your code, you might have something like this:
let hoursWorkedView = HoursWorkedView()
self.view.addSubview(hoursWorkedView)
It's right here where we should be setting the delegate:
let hoursWorkedView = HoursWorkedView()
hoursWorkedView.delegate = self
self.view.addSubview(hoursWorkedView)
Though if it's me, I probably add a constructor to HoursWorkedView that accepts the delegate property:
init(delegate: HoursWorkedDelegate) {
super.init()
self.delegate = delegate
}
And now we can just do this:
let hoursWorkedView = HoursWorkedView(delegate: self)
self.view.addSubview(hoursWorkedView)
I think you're getting your view and your viewcontroller mixed up: a ViewController controls things; a view just displays them. The viewController tells the view what to display.
So, you want to connect your button to the viewController -- not the view. And you don't need a custom view class or a delegate.
Set it up like this:
create a textField and a button
create an outlet for the textField
put calculateHoursWorked directly in your viewController
create an action to connect the button to calculateHoursWorked
in calculateHoursWorked, set self.textField.text to the result of the calculation (where "textField" is whatever you named your outlet)
You wouldn't use a delegate in this context because the viewController knows everything the view does. The delegate pattern is for cases where one object has no visibility into another.
EDIT:
That being said, the bug here is that the delegate isn't actually being set anywhere.
Swift Optionals (the ! and ?) help prevent cases like this. If you explicitly unwrap an optional using !, you have to make sure it's always defined. In this case, since delegate is defined as optional (?) you have to check it:
#IBAction func calculateHoursWorked(sender: AnyObject){
// Do some calculations for the hoursWorked value
// Give value
if let currentDelegate = self.delegate {
currentDelegate.sendHoursWorked(hoursWorked)
}
}

Resources