I am currently trying to set the UImageView of a UIViewController class I defined called MyViewController. In the MyViewController class I have an outlet for the UIImage like so:
#IBOutlet weak var img: UIImageView?
I then try to set it in another class by using:
let vc:MyViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "test") as! MyViewController
vc.imgView!.image = UIImage(named: "wonders1.png")
The problem is imgView is nil when I force unwrap and I'm not sure why since I'm instantiating the view controller
image of my storyboard:
https://i.stack.imgur.com/ubpQN.png
Error I'm getting:
fatal error: unexpectedly found nil while unwrapping an Optional value
You are trying to add image to an UIImageView instance which isn't initialized yet, the views on UIViewController instance is loaded only after func viewDidLoad() function gets called (read more on iOS life cycle here).
So in order to complete your task you should implement this inside MyViewController:
override func viewDidLoad() {
super.viewDidLoad()
vc.imgView.image = UIImage(named: "wonders1.png")
}
Related
So all my controller's are done programmatically to avoid segues and that sort of complicated stuff.
I have a viewcontroller (Call it ProfileViewController) that downloads data from the network.
So I have a method in ProfileViewController that instantiates a single storyboard file with a static tableview with cells that have textfields in them. Here is the method:
ProfileViewController:
func userSelectedUpdateProfile() {
// Obtain reference to the only storyboard file named EditProfileSB
let storyboard = UIStoryboard(name: "EditProfileSB", bundle: nil)
// Since the Tableview is embedded in a navigation controller (with ID set to "navigationID")
if let parentNavigationController = storyboard.instantiateViewController(withIdentifier: "navigationID") as? UINavigationController {
// Now find the embedded TableViewController and access it's properties to pass to.
if let childEditController = parentNavigationController.topViewController as? EditProfileTableViewController {
// ! Error here ! Found nil when doing this.
childEditController.nameTextfield.text = "Passed this to static cell"
}
present(parentNavigationController, animated: true, completion: nil)
}
}
So the code itself is self-explanatory to what I am trying to achieve here. The TableView is embedded in a Navigation (done on storyboard with "Editor > Embed In") so on the 2nd nested if let statement I am now checking to find that Edit controller and access its properties (nameTextfield).
I get a crash when I attempt to access the nameTextField.text property. This textfield is set using storyboard. Here is that EditProfileTableViewController:
class EditProfileTableViewController: UITableViewController {
#IBOutlet weak var nameTextfield: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
// Other methods ...
}
Here is the storyboard flow layout.
Am I missing something here? I keep getting a crash on childEditController.nameTextfield.text = "Passed this to static cell" on the method userSelectedUpdateProfile().
If your View Controller still not call viewDidLoad().
your textfield is not create.
#IBOutlet weak var nameTextfield: UITextField!
you can see it's attribute is weak here.
Try create a value and pass text to the value. Then in viewDidLoad(), you can set the value to your textField
Evening I have a problem with outlets.
viewController1 make several instances of ViewController2, presenting them into a page container controlled with a pageControl.
The problem is that the view controller outlets in the ViewController2 are always nil.
Probably because the ViewController2 is instantiate via code.
How can I fix this?
here I create the different ViewController2
let page = OnboardPageViewController(onboard: onboard)
pages.append(page)
Here is the init code for ViewController2
//--------------------
//MARK: - Outlets
//--------------------
#IBOutlet var backgroundVideoView: BackgroundVideo!
#IBOutlet var backgroundUIImage: UIImageView!
#IBOutlet var titleLabel: UILabel!
#IBOutlet var descriptionLabel: UILabel!
//--------------------
//MARK: - Properties
//--------------------
let onboard: Onboard
//--------------------
//MARK: - View's Methods
//--------------------
override func viewDidLoad() {
super.viewDidLoad()
print("loaded: \(onboard.title)")
//FIXME: - need to find a way to link the outlets even if the controller is called via code
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
print("presenting: \(onboard.title)")
}
init(onboard: Onboard) {
self.onboard = onboard
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
You have to instantiate through UIStoryboard object, something like this:
if let viewController = UIStoryboard.init(name: "YourStoryBoardName", bundle: nil).instantiateViewController(withIdentifier: "YourViewController") {
// do something with it
}
You can cast it to your custom class in at the same time of the unwrap (with as? CustomClassViewCotroller)
Edit: static func to instantiate your view controller like init:
class YourViewController: UIViewController {
static func instantiate(withViewModel vm: ViewModel) -> YourViewController? {
if let viewController = UIStoryboard.init(name: "YourStoryboard", bundle: nil).instantiateViewController(withIdentifier: "YourViewController") as? YourViewController {
viewController.viewModel = vm
return viewController
}
return nil
}
var viewModel: ViewModel?
// ...
}
There will be more optional unwrapping in your code when using viewModel var but I think this is the correct way to create view controllers programmatically (in segues you have to set variables too, but that is another history).
Good luck mate.
Your outlets will be nil until the Storyboard file is loaded. So, right after init, they will be nil. You have to wait until viewDidLoad is called before accessing them.
If you need to init and set up things in the VC, you have to add other (non outlet) properties to hold that information. You can't just init and then access an outlet.
EDIT: In your code (added later), you aren't using a XIB or Storyboard. But, since you have outlets, I am assuming that you actually have one.
Don't use a custom init. Instead add properties and set them after you initialize using a Storyboard instantiate.
I have a view controller OtherUserAccountViewController containing a button with a "profile picture" as its background. When this button is tapped, I would like to push a new view controller ImageTappedViewController onto the stack to simply present a bigger ImageView of this said profile picture. Please note the Storyboard identifier for the screenshot seen below is in fact "imageTapped" and the class is ImageTappedViewController
Below is my function for instantiating and pushing the new view controller:
In OtherUserAccountViewController.swift:
#IBAction func profilePicButtonTapped() {
let sb = UIStoryboard(name: "SuccessfulLogin", bundle: nil) //SB name: SuccessfulLogin
let cc = (sb.instantiateViewController(withIdentifier: "imageTapped")) as! ImageTappedViewController
if cc.imageView == nil || cc.imageView == UIImage() {
print("Nil") //<- Nil is printed upon firing this function
} else {
print("not nil")
}
//cc.imageView.image = self.profilePicButton.currentBackgroundImage <- breaks because the imageView is nil
self.navigationController?.pushViewController(cc, animated: true)
}
ImageTappedViewController.swift:
import UIKit
class ImageTappedViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
I am totally lost as to why this imageView is returning nil.
I set the imageView to display the lovely Taylor Swift on default as seen below; but regardless, nil is being returned.
Any help is much appreciated!
When view controllers are first initialized their IBOutlets will not be initialized. Only after viewDidLoad will all of their outlets be non-nil. Pass the image as a UIImage then in viewDidLoad set image view's image property.
I have two simple ViewController: the first one has a IBOutlet linked to a UIImageView and a function that sets the image alpha channel. The second controller has a button that, when it's trigged, should call the function to set the alpha channel.
Here my code:
class FirstViewController: UIViewController {
#IBOutlet imageView: UIImageView!
func changeAlphaChannel() {
imageView.alpha = 0.5
}
}
class SecondViewController: UIViewController {
let firstController = FirstViewController()
#IBAction func buttonPressed(sender: UIButton) {
firstController.changeAlphaChannel()
}
}
Calling changeAlphaChannel() inside FirstViewController works as aspected, but if I call it pressing the button, imageView becomes nil and the app crashes.
How can I fix this?
Thanks
Its crashing because your imageView is nil. Just initialising firstController with FirstViewController() will not do. You'll have to load that view controller from storyboard. You can do it this way
let storyboard: UIStoryboard = UIStoryboard.init(name: "StoryboardName", bundle: nil)
let firstViewController: FirstViewController = storyboard.instantiateViewControllerWithIdentifier("StoryboardIdentifier") as! FirstViewController
UPDATE
Now IBOutlets of firstViewController will be set only when firstViewController's view is instantiated, which in your case is not happening. What you have to do is first display view of firstViewController and then call your function.
You're not calling the function on the first controller - you're creating a new instance of the first controller, which doesn't have anything set in the image.
You need to pass a reference to the first controller through to the second.
In swift we need to check operators are nil or not, try this
imageView?.alpha = 0.5
instead of
imageView.alpha = 0.5
So I have a log in function that goes to parse and validates log in. Then when it returns I present a different view with the following code.
var storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil);
var vc: UIViewController = storyBoard.instantiateViewControllerWithIdentifier("ProfileView") as UIViewController
println("got here");
self.presentViewController(vc, animated: true, completion: nil);
println("got here too");
got here prints to the console got here too does not, the view did load function for ProfileView never gets called. There are no errors in the log and no warnings during compilation. the application does not crash I can keep trying to log in but it will never load the next view or print the second message.
The code did work but then I altered the ProfileView a little bit and it stops. I have reverted the view and its still broken, I have cleaned and rebuilt. Is there anything I should be looking for specifically?
Upon request here are the top lines of ProfileView.
class ProfileView: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var profileImage: UIImageView!
var profilePic: PFObject!
var imageArray: [PFObject]!
when I instantiate those objects with an init method the init method will run and I can break point it but the view will not load cause I never hit the break point on the first line of viewDidLoad.
It looks like the Storyboard Identifier is not set to ProfileView in Interface Builder. Also, in the event you want to set Profile View controller specific properties, you shouldn't cast as UIViewController instead use the class of your Profile View Controller
It might also help to have a UIStoryboard extension that loads your view controllers via helper methods e.g.
extension UIStoryboard {
class func loadProfileViewController() -> ProfileViewController {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateViewControllerWithIdentifier("ProfileView") as! ProfileViewController
}
}
This way you can write let profileVC = UIStoryboard.loadProfileViewController()