How to update UI in swift from a method [duplicate] - ios

This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 6 years ago.
I am new to swift, I am writing an app which needs to change images in the storyboard. i have written a function to change images in the image view. In the function there is an if condition the image should be changed when the if condition is satisfied, but i got "unexpectedly found nil while unwrapping optional value" error when if condition is executed.
import UIKit
import MessageUI
import Foundation
import CoreLocation
class ViewController: UIViewController {
#IBOutlet var F_IMG: UIImageView!
#IBOutlet var FL_IMG: UIImageView!
#IBOutlet var FR_IMG: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
TimeService.initial(viewcontroller: self)
}
public func showImages(){
var type: String = Otherclass.gettype()
setImageForType(type:type)
}
public func setImageForType(type:String){
if (type == "NONE"){
DispatchQueue.main.async {
self.F_IMG.image = UIImage(named: "r_f")
}
"The showImage() function is called in another class."
I have the image in the bundle, but my UI is not getting updated and it always shows the error "unexpectedly found nil while unwrapping optional value"

Make sure FrontImg is properly connected to Storyboard or correctly initialised through code.
Update:
As it turns out, you're calling showImages() from other class, hence it is giving nil error.
By calling ViewController.showImages() from other class, you are creating a new ViewController, not referencing an existing one. This new one doesn't have a F_IMG(imageView) yet because its view hasn't been built. You reference self.F_IMG.image is nil.
My advice is to use NSNotificationCenter for updating UI in other View Controller.
For more approaches, refer this SO Answer

I believe the problem was caused in this line :
self.FrontImg.image = UIImage(named: "r_f")
If you check the Apple Docs on UIImage class, the initializer you are using init?(named name: String) actually returns optional.
So, have you tried
self.FrontImg.image = UIImage(named: "r_f")!

The only thing here which I have found to make sure your UIElement FrontImg must be connected properly.

Related

Why does my app crash when I use an "if let" statement to unwrap an optional collectionViewCell?

I am getting this error in xcode after months of this code working fine, and I can't for the life of me figure out why the code is throwing the error.
Error: Thread 1: Fatal Error: Unexpectedly found nil while unwrapping an Optional value
if let recentsRow = collectionView(collectionView, cellForItemAt: recentsIndex) as? DashboardRowCollectionViewCell {
recentsRow.documents = recents ?? []
}
if let favoritesRow = collectionView(collectionView, cellForItemAt: favoritesIndex) as? DashboardRowCollectionViewCell {
favoritesRow.documents = favorites ?? []
}
Sorry if this has already been asked, but I looked around the site for a while and still was unable to come up with a solution.
Edit: I do not have this issue when running the app in a simulator. I also didn't have this issue before I updated XCode.
Edit 2: The debugger has told me that collectionView is nil, but I am still unsure as to why it is nil.
Here is how collectionView is defined in my ViewController: #IBOutlet weak var collectionView: UICollectionView!
While I am not sure why the collectionview was nil in the first place, I fixed my application from crashing by surrounding the offending code with the following:
if collectionView != nil {
... code goes here ...
}
This will be the accepted answer until someone comes along to explain why it was nil to begin with.
Edit: If you are trying to figure out why it was nil and want the ViewController code that the problem belongs to, I'll be happy to provide it.

Objective-C & Swift 2.0 and "paranoic" Class

On a Project i use Objective-c 2.0-Swift2.0 and XCode 7.0.
So the matter is:
I'm tryin to put some string gotten from txt file in order to be shown into a UiTextView object.
The catch from another Object-C call was fine.
The reading of the file txt Was fine
...but the putting String into the UITextView! returns me always Nil. It's a dummy work but... it's still not work!
I tried to do the same as single Application Swift File: it works!
p.s. Notice i did a IBoutlet to connect the UIView Object into the StoryBoard to this Class.
Here's the code, if you need more details i would be happy to provide this.
import UIKit
#objc(TextControllerSwift) class TextControllerSwift: UIViewController {
var textRoom: String?
var textPlaying: String?
#IBOutlet weak var textMuseum: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
realplay()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func playText(textSelect: String) {
//textSelect REturn a string value from another Object-C Class -See comments in the Segue add in.
textPlaying = textSelect
}
func realPlay(){
let path = NSBundle.mainBundle().pathForResource(textPlaying, ofType:"txt")
if (path != nil){
//read the file
do {
let textRoom = try NSString(contentsOfFile: path!, encoding: NSUTF8StringEncoding)
print(textRoom)
}
catch {/* let's ignore when i didn't find file */}
textMuseum!.text="pippo" //Nil
print(textMuseum!.text) //Nil
textMuseum.text=textMuseum.text.stringByAppendingString(String(textRoom)) //Nil
}
}}
it give me
"fatal error: unexpectedly found nil while unwrapping an Optional value"
Why? Why? in the same project i call another Swift Class and it works really fine. (AKA i followed the guideline for coexisting Swift&Objective-C classes)
Thanks a lot in advance for your answers.
EDIT: Added info about the Caller from Objective-C, maybe this helps.
`if ([segue.identifier isEqualToString:#"segueIntroTesto"]) {
NSLog(#"%# in segueIntroTesto" , selectedIntroFilm);
TextControllerSwift *destViewController = segue.destinationViewController;
[destViewController playText:selectedIntroFilm];
}`
EDIT2:: removed *self.viewDidLoad()* under playText func.
EDIT3:: splitted the function playText() into another Function to give time to XCode (uffff) to get the new View then i REMOVED the old damned Outlet :D ...cheers I solved Thanks
Your problem is that you're trying to set the value of an outlet before the view gets loaded. Preparing for a segue happens before outlets are filled in.
Pass selectedIntroFilm into the controller and save it as a property during the segue, then call playText later...during viewDidLoad or viewWillAppear or whatever makes sense for the app.

WatchKit "unexpectedly found nil while unwrapping an Optional value" when accessing IBOutlet in Glance on actual device

I have a Glance and some WKInterfaceLabels. I use setHidden() on them in override func willActivate() depending on some conditions.
class GlanceController: WKInterfaceController {
#IBOutlet weak var lName: WKInterfaceLabel!
...
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
if(conditions) {
lName.setHidden(false)
} else {
lName.setHidden(true)
}
}
}
This works in simulator but on actual watch, I get fatal error: unexpectedly found nil while unwrapping an Optional value at lName.setHidden().
Anyone saw this before?
As your "lName" is declared as explicitly unwrapped optional, it safer to access the variable following way -
if let validLName = lName {
if(conditions) {
validLName.setHidden(false)
} else {
validLName.setHidden(true)
}
}
}
It appears that you are not allowed to use .setHidden() in Glance, at least for the current version of WatchKit.
I redesign my UI completely to use a single label and it works. Obviously it does not look as nice as I intend.
I understand the restriction but really hope there is more documentation to save the trouble. Just like I only found out I can't scroll in Glance after spending time designing the UI.

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:

Accessing an IBOutlet from another class

I am new to Swift/iOS, so please bear with me:
I am trying to access a function in one class from another class, and update an UIImage name.
Within my viewcontroller class I have
class Documents: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet var UpdateImage: UIImageView
override func viewDidLoad() {
super.viewDidLoad()
UpdateImage()
}
func UpdateImage() {
UpdateImage.image = UIImage(named: "NewImage")
}
}
Everything works, the Image gets updated to "NewImage"
Question: I can access the UpdateImage func from another class, but why is it generating an error when trying to change the image in the Documents class?
class GetChanges {
var success = { operation:AFHTTPRequestOperation!, response:AnyObject!) -> Void in
var MakeChange = Documents()
MakeChange.UpdateImage()
}
}
This generates an error on the "UpdateImage.image = UIImage(named: "NewImage")" in the Documents Class; "fatal error: unexpectedly found nil while unwrapping an Optional value"
When you call it within the class itself, it is operating on itself and it has already been created from a nib/storyboard. This means that UpdateImage exists.
When you call the method from another class, when you call this line:
var MakeChange = Documents()
You are creating a new instance of Documents. This is not initialized through the nib/storyboard, and thus it never populated the IBOutlet value UpdateImage. Because this value doesn't exist, it unexpectedly finds nil and throws an error.
You need to somehow retain a reference to the instance of Documents you're trying to display. I'd need more information to tell you how to do that.
Also, because you mentioned that you're new, I'd like to point out a few issues I notice with your code that is making it very difficult to read.
Capitalized names are reserved for Types variable names should (almost) never begin with a capital letter.
Variable names should reflect the object they represent. UpdateImage sounds like it is an image. It would be better to name this updateImageView
Functions should be lowercase as well. It is strange to see capitalization this way and makes the code a bit uncomfortable to read.
Good luck!
Read about View Contoller's lifecycle, it's very important knowledge for iOS developer.
As Logan said:
You are creating a new instance of Documents. This is not initialized through the nib/storyboard, and thus it never populated the IBOutlet value UpdateImage
This means that after call init for ViewController (i.e. Documents()) nib isn't loaded. You can use outlets of viewController in another code only after viewDidLoad stage. Apple docs:
The nib file you specify is not loaded right away. It is loaded the first time the view controller's view is accessed. If you want to perform additional initialization after the nib file is loaded, override the viewDidLoad() method and perform your tasks there.
You can remove MakeChange.UpdateImage(), because it will be called in viewDidLoad. Or, if you want pass specific image name to view controller:
class Documents: UIViewController, UITableViewDataSource,
UITableViewDelegate {
#IBOutlet var UpdateImage: UIImageView
var imageName: String?
override func viewDidLoad() {
super.viewDidLoad()
updateImageView()
}
func updateImageView() {
if let imageName = imageName {
UpdateImage.image = UIImage(named: imageName)
}
}
}
After that, you can use
let documentsViewController = Documents
documentsViewController.imageName = "newImage"
When you load documentsViewController, newImage will be presented

Resources