UIImageView is not instantiated in DetailViewController - swift

I am writing a master-detail application. When table row item is clicked, I load the image in the DetailViewController, which has a UIImageView. I assume the UIImageView is instantiated by app and I only need to set the UIImage.
imageView.image = UIImage(name:"camera")
However, the imageView is nil. I sure that the imageView is linked with UIImageView on storyboard.
#IBOutlet weak var imageView: UIImageView!
func configureView() {
if !imageView {
println("nilnilnil") // nilnilnil is printed...
}
}

You need to make sure that the view has already been loaded. You should at least wait until after viewDidLoad. Usually you would do this directly in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
self.imageView.image = UIImage(name: "camera")
}
This is because the subviews are not created and the connections are not setup until the view is loaded. The view is not loaded until the view property of the view controller is accessed – usually, this is when the view controller is presented for the first time.
Minor Note: A variable is "instantiated" or "initialized" not "instanced"

Related

Why when I pass data to a UILabel directly in the Second View Controller it turns to be nil?

Why when I pass data to a UILabel directly in the Second View Controller it turns to be nil but when I pass data to a variable first and then apply it to the UILabel everything works fine?
The following code crash the app after segue performed (theResult is nil):
Second View Controller:
#IBOutlet weak var theResult: UILabel!
Main View Controler:
secondVC.theResult.text = “Nice”
But when I create a variable in the Second View Controller, I can pass the data to it easily and then apply it to the UILabel without any problem:
Second View Controller:
var calculation: String?
#IBOutlet weak var theResult: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
theResult.text = calculation
}
Main View Controler:
secondVC.calculation = “Nice”
Why is that?
Note: The UILabel has a default value already when it is created in the Storyboard.
I am almost sure that this is not working but I want to know the reason. Why you can easily change for example the background of the Second View Controller like this:
secondVC.view.backgroundColor = .green
but when you touch the IBOutlets it do not work.

UIButton inside table cell not changing attributes

I have a UIButton inside my cell together with an image and a text label. I manage to change the image and label programatically, but the UIButton does not seem to respond to anything except isHidden.
This is my code, the button that is not changing is followButton:
import UIKit
class ProfileTableCell: UITableViewCell {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var profileImage: UIImageView!
#IBOutlet weak var followButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
self.profileImage.layer.borderWidth = 0.0;
self.profileImage.layer.cornerRadius = self.profileImage.frame.size.width/2;
self.profileImage.clipsToBounds = true
self.profileImage.image = UIImage(named: "belt")
self.name.text = "Bar Refaeli"
self.followButton.layer.borderColor = UIColor.black.cgColor
self.followButton.layer.borderWidth = 3.0;
self.followButton.layer.cornerRadius = self.frame.size.width/4
self.followButton.backgroundColor = UIColor.black
}
func setCell(image: UIImage, name: String){
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
The profileImage and name outlets change the appearance fine, like mentioned above.
I also tried to remove the button and bring it back in, clean xcode project, remove the outlet reference and connecting it again. Pretty frustrated by now.
I also tried to change the background color of the button through the storyboard, just for testing, and it does not change it! what does change is the titleLabel and the text color.
awakeFromNib()- Prepares the receiver for service after it has been loaded from an Interface Builder archive, or nib file.
Given that, move your code to a view initiating method like viewDidLoad or viewDidAppear(_:)
Child objects that are attributes like textLabels act differently than child view objects.
Eventually I actually solved this by tossing the table view to the garbage and implementing the same needs using a collection view. there was no problem there..

how to set background colour of a container view

i have dragged a container view from storyboard and set it black in background colour. but it didn't change the background colour.
class ViewController: UIViewController {
#IBOutlet weak var container: UIView!
override func viewDidLoad() {
super.viewDidLoad()
container.layer.backgroundColor = UIColor.blackColor().CGColor
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
How did you set the background color?
A container view is actually just a normal view, that is linked to a viewController. This means you can set the background the same way as you would for any other NSView or UIView. This is all the code I needed to add to my NSViewController class (not the ViewController inside the container, just the ViewController for the window).
#IBOutlet weak var containerView: NSView!
override func viewDidLoad() {
//other code in your viewDidLoad
containerView.wantsLayer = true
}
override func awakeFromNib() {
super.awakeFromNib()
containerView.layer?.backgroundColor = NSColor.black.cgColor
}
make sure to connect the IBOutlet if you have not already.
If you set the layers background color in viewDidLoad, the layer may not exist yet, (I don't know why). Accessing the layer in awakeFromNib has always worked for me, while accessing it in the viewDidLoad can be unreliable.
If you are working on IOS, most of this is not applicable, and this should be all you need
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
containerView.layer?.backgroundColor = UIColor.black.cgColor
}
I work less on IOS, so I have not ran into any issues with that, but that could be from lack of attempts. On OSX setting the background color in viewDidLoad will work about 50% of the time so there might still be an issue that I have not ran into.
If neither works, try unwrapping the layer rather than leaving it an optional (replacing the ? with a !) this will at least crash your program and probably tell you that layer is nil, if this is the case you should be figuring out why the layer is nil.
Also if the ViewController connected to the container view is a custom class, you don't have to bother with the IBOutlets, just call the view "view" in that custom class.
Sorry this got a bit long, but hope this helped

How to change content view of Window?

I am developing an mac osx application which have initial window and viewcontroller launched from main storyboard. I want to replace the content view loaded by storyboard with my view.
I am doing this -
func replaceContentView() {
parentViewController = MainViewController(nibName: "MainContainerView", bundle: nil)!
let fullScreenFrame = NSScreen.mainScreen()?.visibleFrame
self.initialWindow.setFrame(fullScreenFrame!, display: false, animate: false)
self.initialWindow.contentView = parentViewController! . view
}
Problem with this approach is that the default viewcontroller is never getting deallocated. deinit() of default viewController is not called at all.
This is causing memory leak. So how to completely remove default content view and associated viewcontroller?
Storyboards don't deal in views, they deal in viewcontrollers. What a Storyboard does when it loads a view into a window is that it creates an NSViewController and then goes
windowController.contentViewController = theViewController
That implicitly also inserts theViewController.view as the window's content view. So do the same, and all will be fine.
Marek's example is wrong, because CustomView shouldn't be an NSView subclass, it should be a CustomViewController class that owns a view containing the label etc. As a bonus, NSViewController will take care of loading the XIB for you as well.
Alternately, you could set windowController.contentViewController = nil (which will remove the old view controller and its content view) and then set your content view. But really, why fight the framework when that's exactly what NSViewController is intended for?
You can write the code in deinit method,may it will help you.
deinit {
// perform the deinitialization
}
Your contentViewController within NSWindow instance still holds strongly its old view. You have replaced just property on your NSWindow instance.
To clarify what you have done:
NSWindow holds strongly against new view
NSViewController holds strongly against old view
You should assign your new view into contentViewController.view property as well
This might be helpfull:
NSWindow.h
/* NSViewController Support */
/* The main content view controller for the window. This provides the contentView of the window. Assigning this value will remove the existing contentView and will make the contentViewController.view the main contentView for the window. The default value is nil. The contentViewController only controls the contentView, and not the title of the window. The window title can easily be bound to the contentViewController with the following: [window bind:NSTitleBinding toObject:contentViewController withKeyPath:#"title" options:nil]. Setting the contentViewController will cause the window to resize based on the current size of the contentViewController. Autolayout should be used to restrict the size of the window. The value of the contentViewController is encoded in the NIB. Directly assigning a contentView will clear out the rootViewController.
*/
#availability(OSX, introduced=10.10)
var contentViewController: NSViewController?
/* The view controller for the window's contentView. Tracks the window property of the same name.
*/
#property (strong) NSViewController *contentViewController NS_AVAILABLE_MAC(10_10);
However what you do seems incorrect if you do this on launch.
You either set custom subclass of contentView to your new nsview subclass which can load it's view from another XIB (no need for storyboard).
Abstract example:
class CustomView: NSView {
#IBOutlet var contentView: NSView!
#IBOutlet weak var label: NSTextField!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
initSubviews()
}
func initSubviews() {
let nib = NSNib(nibName: "CustomView", bundle: nil)
nib.instantiateWithOwner(self, topLevelObjects: nil)
contentView.frame = bounds
addSubview(contentView)
}
}
PS: topLevelObjects is set to nil because you hold strongly contentView. So no need to worry about memory management.

Swift: Refreshing UIImageView Image

Half of my window is a UITableView and other is a PageViewController.
In my PageViewController, I have two properties:
#IBOutlet weak var displayImageView: UIImageView!
var displayImage : UIImage?
PageViewController viewDidLoad I assign:
override func viewDidLoad() {
super.viewDidLoad()
self.displayImageView.image = self.displayImage
}
displayImageView is an outlet connected to my scene in Storyboard. As the User taps different cells, I would like the image in displayImageView to change.
In my parentViewController that displays the tableView and the PageViewController, I call the following method in my didSelectRowAtIndexPath
func getDisplayImageForSelectedRow() {
var row = self.tableView.indexPathForSelectedRow()?.row
//DisplayImageVC is a contentViewController that is loaded by pageViewController
var displayImageVC = self._pageContent[1] as DisplayImageVC
displayImageVC.displayImage = self._displayImage[row!] as UIImage
println(displayImageVC.displayImage)
if (self.isPageViewVisible){
displayImageVC.displayImageView.reloadInputViews()
displayImageVC.displayImageView.setNeedsDisplay()
}
}
Here the log from println():
You selected cell #0
Optional(<UIImage: 0x7c21c2e0>)
You selected cell #1
Optional(<UIImage: 0x7c21c5a0>)
You selected cell #2
Optional(<UIImage: 0x7c21cd00>)
You selected cell #3
Optional(<UIImage: 0x7c21cff0>)
You selected cell #4
Optional(<UIImage: 0x7c21d2d0>)
Based on the log, I presume a new image is being assigned; however, the UIImageView outlet continues to show the same image that was loaded the first time pageViewController was loaded.
As you may have noticed in the code, I have tried the following lines to code to get the UIImageView to refresh, but no avail:
displayImageVC.displayImageView.reloadInputViews()
displayImageVC.displayImageView.setNeedsDisplay()
How can I get the UIImageView to show the new image that was loaded?
In getDisplayImageForSelectedRow you are only updating the UIImage, you should also assign the image to the view.:
func getDisplayImageForSelectedRow() {
..
displayImageVC.displayImage = self._displayImage[row!] as UIImage
displayImageVC.displayImageView.image = displayImageVC.displayImage <--THIS
..
}