Could Not Cast Value of Type Uiview to [Customview] Using Xib

Could not cast value of type 'UIView' to 'SCNView'

Make sure to also import SceneKit at the top of the file.

import SceneKit

Open the “Main.storyboard” File. Select ViewController -> View go to “Identity Inspector” and change the Class field to SCNView.
SceneKit Help

Cannot cast my custom UIView subclass created from XIB to the class I need (only UIView)

In Interface Builder, did you change the class name in the Identity Inspector (3rd from left) tab from UIView to your custom class name?
screen grab of IB

Could not cast value of type 'UIView' to 'SKView' (removed Storyboard)

This is where your mistake is:

let skView = view as! SKView

You are assuming that self.view is an instance of SKView, but it isn't. It's a UIView, just like how in the storyboard, the root view by default has the class UIView.

You should instead do:

let skView = SKView()
view = skView

To set the root view to an instance of SKView.

accessing UIView subclass in view controller

Posting my own answer.

  1. Create the XIB file.
  2. Create the UIView subclass Swift file.
  3. Under the XIB file owner's Identify Inspector custom class field, type in the UIView subclass name (your custom view).
  4. Under the XIB file owner's Connections Inspector, make sure all IBOutlets in the Swift file are connected.
  5. Add a view to the view controller and under its Identify Inspector custom class type, specify the custom class name.

Important:
* In your XIB swift file, you have to properly load the XIB content view.

...

/// Initializer used by Interface Builder.
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}

/// Initializer used programmatically.
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}

...

func configure() {
let contentView = // here use many of the functions available on the internet to
// load a view from a nib.
// Then add this view to the view hierarchy.
addSubview(contentView)
}

Load a UIView from nib in Swift

Original Solution

  1. I created a XIB and a class named SomeView (used the same name for
    convenience and readability). I based both on a UIView.
  2. In the XIB, I changed the "File's Owner" class to SomeView (in the identity inspector).
  3. I created a UIView outlet in SomeView.swift, linking it to the top level view in the XIB file (named it "view" for convenience). I then added other outlets to other controls in the XIB file as needed.
  4. in SomeView.swift, I loaded the XIB inside the "init with code" initializer. There is no need to assign anything to "self". As soon as the XIB is loaded, all outlets are connected, including the top level view. The only thing missing, is to add the top view to the view hierarchy:

.

class SomeView: UIView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSBundle.mainBundle().loadNibNamed("SomeView", owner: self, options: nil)
self.addSubview(self.view); // adding the top level view to the view hierarchy
}
...
}

Note that this way I get a class that loads itself from nib. I could then use SomeView as a class whenever UIView could be used in the project (in interface builder or programmatically).

Update - using Swift 3 syntax

Loading a xib in the following extension is written as an instance method, which can then be used by an initializer like the one above:

extension UIView {

@discardableResult // 1
func fromNib<T : UIView>() -> T? { // 2
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else { // 3
// xib not loaded, or its top view is of the wrong type
return nil
}
self.addSubview(contentView) // 4
contentView.translatesAutoresizingMaskIntoConstraints = false // 5
contentView.layoutAttachAll(to: self) // 6
return contentView // 7
}
}
  1. Using a discardable return value since the returned view is mostly of no interest to caller when all outlets are already connected.
  2. This is a generic method that returns an optional object of type UIView. If it fails to load the view, it returns nil.
  3. Attempting to load a XIB file with the same name as the current class instance. If that fails, nil is returned.
  4. Adding the top level view to the view hierarchy.
  5. This line assumes we're using constraints to layout the view.
  6. This method adds top, bottom, leading & trailing constraints - attaching the view to "self" on all sides (See: https://stackoverflow.com/a/46279424/2274829 for details)
  7. Returning the top level view

And the caller method might look like this:

final class SomeView: UIView {   // 1.
required init?(coder aDecoder: NSCoder) { // 2 - storyboard initializer
super.init(coder: aDecoder)
fromNib() // 5.
}
init() { // 3 - programmatic initializer
super.init(frame: CGRect.zero) // 4.
fromNib() // 6.
}
// other methods ...
}
  1. SomeClass is a UIView subclass that loads its content from a SomeClass.xib file. The "final" keyword is optional.
  2. An initializer for when the view is used in a storyboard (remember to use SomeClass as the custom class of your storyboard view).
  3. An initializer for when the view is created programmatically (i.e.: "let myView = SomeView()").
  4. Using an all-zeros frame since this view is laid out using auto-layout.
    Note that an "init(frame: CGRect) {..}" method is not created independently, since auto-layout is used exclusively in our project.
  5. & 6. Loading the xib file using the extension.

Credit: Using a generic extension in this solution was inspired by Robert's answer below.

Edit
Changing "view" to "contentView" to avoid confusion. Also changed the array subscript to ".first".

How to initialize/instantiate a custom UIView class with a XIB file in Swift

I tested this code and it works great:

class MyClass: UIView {        
class func instanceFromNib() -> UIView {
return UINib(nibName: "nib file name", bundle: nil).instantiateWithOwner(nil, options: nil)[0] as UIView
}
}

Initialise the view and use it like below:

var view = MyClass.instanceFromNib()
self.view.addSubview(view)

OR

var view = MyClass.instanceFromNib
self.view.addSubview(view())

UPDATE Swift >=3.x & Swift >=4.x

class func instanceFromNib() -> UIView {
return UINib(nibName: "nib file name", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}


Related Topics



Leave a reply



Submit