Bug with class names in xcode/swift? - ios

Created the following files (view with xib and view controller):
SomeViewController.swift
SomeView.swift
SomeView.xib
NOTE: The names may differ but the class names should look similar as in this example.
SomeViewController is just a subclass of UIViewController and is not linked with SomeView at all.
But when I use SomeViewController it somehow calls awakeFromNib() in SomeView and it causes crash. Checked twice - the bug won't appear if I for example change class name from SomeViewController to SomeViewController2.
Code for my case:
let vc = SomeViewController()
... //add it to UITabBarController
Must I rename it to something fully different or can I somehow fix this link between view and view controller?

https://developer.apple.com/documentation/uikit/uiviewcontroller/1621487-nibname
If the view controller class name ends with the word ‘Controller’, as
in MyViewController, it looks for a nib file whose name matches the
class name without the word ‘Controller’, as in MyView.nib.
Solution:
class SomeViewController: UIViewController {
override var nibName: String? {
return nil
}
}

Related

One storyboard for few view controllers

I have a storyboard, and it needs to be used in few places. Is there any other option than just duplicate storyboard and assign it to new view controller? I want to avoid boilerplate code and writing 3x same outlets and others. I need exactly same layout and almost all functions in all three controllers, but I want to only change model for all of them.
I have tried to do it like this:
class FirstViewController: UIViewController {
//outlets
// code
// tableView configuration
}
class SecondViewController: FirstViewController {
// and here I have just overrided some function to modify them
}

In iOS, how to get the name of a UIStoryboard?

If I have reference to a UIStoryboard object, how do I get its name?
For example if I have
class ProfileVC: UIViewController {
override func viewDidLoad() {
let name = self.storyboard?.name // public .name property does not exist
let name = self.storyboard?.value(forKey: "name") // private property access works
}
}
Is there a way to get the name publicly? If not, why did Apple make this private?
Edit: Add use case
The app has multiple storyboards and there is navigation code that is able to navigate to a particular storyboard: navigate(to storyboardName: String). This code always instantiates a new storyboard object and its initial view controller. This is causing bugs in the UI.
I want to do a check to see if the window's root view controller's storyboard is the same as the destination storyboard to prevent re-instantiation.

Instantiation of ViewControllers from storyboard in Swift

I have a UIViewController that looks a bit like this:
class ProfileViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, ... {
...
convenience init(name: String) {
print("Init with student: \(name)")
self.init()
}
...
}
I have a corresponding Storyboard layout for this, embedded in a UINavigationViewController, linked to a UITabBarController. This seemed like the easiest way to design the layout, and is great for when there's only one instance of this VC required (which is how the app was originally designed).
I'd now like to create multiple tabs from this single design (between 1 and 3), and pass the VC init information programatically, but I'm unsure exactly of the best way to do this - as you can see above I've added a convenience init function based on some reading I've done as that seemed like a good place to start.
It's easy enough to create new named tabs based on the storyboard layout like this:
for user in (users)! {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "profileNC")
controller.tabBarItem.title = user.name
newTabs?.insert(controller, at: 0)
}
self.viewControllers = newTabs
But, doing it this way I don't get to call the init function to pass the UIViewController the information it needs to display correctly.
How can I create my ViewControllers, link the layout to the Storyboard and use the custom init function? Is this even possible?
Any suggestions gratefully appreciated!!
When using a storyboard you cannot use a custom initialiser. You will need to either set the property directly or use a configuration function on the view controller instance after you have created it.

Swift: Change Type of View Controller to Something Other than UIViewController

I'm, relatively, a beginner, so this may be an entirely common practice—or an entirely impossible one—but I've been wondering if it's possible to modify a view controller added in a storyboard so that instead of (or in addition to?) being an instance of UIViewConroller, it's also an instance of (blahblah)ViewController, e.g. ABUnknownPersonViewController.
That way, instead of doing something like this:
class ViewController : UIViewController {
override func viewDidLoad() {
let test = ABUnknownPersonViewController()
...
self.presentViewController(test, animated: false, completion: nil)
}
}
This could be done:
class ViewController : ABUnknownPersonViewController {
override func viewDidLoad() {
//ViewController already is an ABUnknownPersonViewController, so you can treat it as one
//example below (displayedPerson is a property of ABUnkownPersonViewControllers)
self.displayedPerson...
}
}
EDIT: ABUnknownPersonViewController is a class supplied by Apple, which does not support subclassing (here). With that said, and the understanding that I would obviously like as simple a solution as possible (avoidance of protocols and whatnot), what are my options?
I tried class FourthViewController: UIViewController, ABUnknownPersonViewController, ABUnknownPersonViewController, ABUnknownPersonViewControllerDelegate only to get an error about multiple inheritance.
It sounds like what you actually want to do is to subclass UIViewController, and in your storyboard, set the custom class to your subclass. When the view controller is loaded from the storyboard, it will be an instance of your subclass.
So your subclass would look like this:
class ABUnknownPersonViewController : UIViewController {
override func viewDidLoad() {
self.displayedPerson...
}
}
In the storyboard, highlight the view controller you want to use a custom class for, and in the Custom Class field, type the name of your subclass. If you've done it correctly, it should autocomplete for you.

Changing view from custom class

I have a custom class. It loads when the app starts. I have to change the view inside this class method.
Class:
import Foundation
class ChatManager {
class var sharedInstance: ChatManager {
struct Singleton { static let instance = ChatManager() }
return Singleton.instance
}
override init() {
super.init()
}
function changeView() {
//I need to change view here.
}
}
I can change the view inside a view controller but this class is not an UIViewController
What should I do ?
My suggestion would be to do it in UIViewController. Your class should not be responsible for the View part.
But that's not your question. What you could do is send YourView as a parameter to the function do some logic there and return it. If you have to resize YourView on several different location, then create method for that inside YourView class. If you use same logic for several different UIViews create BaseView and implement that method there, and then inherit in your views BaseView.
I have to mention it again, this is not the place to do any UI-related stuff.
This is how you pass your UIView through. I agree with Nick however, you should be doing View logic in a custom View class or the UIViewController class.
function changeView(yourView: UIView) {
//I need to change view here.
}
I agree with Nick. The answer is, don't. You should treat a view controller's views as private. Mucking around with a view controller's views violates the OOP principle of encapsulation.
If you insist on having an outside class make changes to your views, create an instance method in your class that takes a view as a parameter and then applies changes to that view. Then you can call the method from your view controller class to make changes to your view.
Here is a solution that requires a navigation controller. If you are unfamiliar with navigation controllers, I strongly recommend looking at a tutorial. They make life much easier for iOS developers. Sorry if that code is running off your screen.
// Switches to MyViewController, a class I have implemented somewhere else
func moveToMyView() {
if let navController = getNavigationController() {
// The Identifier was set in the Identity Inspector tab on the storyboard (The field is called "Storyboard ID")
if let myController = navController.storyboard?.instantiateViewControllerWithIdentifier( "myClassID" ) as? MyViewController {
// Switch to the newController
navController.pushViewController( exerciseController, animated: true )
}
}
}
// Returns the navigation controller if it exists
func getNavigationController() -> UINavigationController? {
if let navigationController = UIApplication.sharedApplication().keyWindow?.rootViewController {
return navigationController as? UINavigationController
}
return nil
}

Resources