简体   繁体   中英

Cannot Call Value of Non-Function Type 'UICollectionView' in Swift 3

Intended Outcome

A generic private method for creating tabbbar icons in a custom tabbar controller. Should successfully paint the tabbar icons for each indicated controller.

Result

Fails with

Cannot Call Value of Non-Function Type 'UICollectionView'

Failing (Generic) Code:

private func createNavController(imageName: String, _ controllerName: UICollectionViewController) -> UINavigationController {

               let layout = UICollectionViewFlowLayout()
Thrown Here->  let viewController = controllerName(collectionViewLayout: layout)
               let navController = UINavigationController(rootViewController: viewController)
               navController.tabBarItem.image = UIImage(named: imageName)

               return navController


       }

Working (non-generic) Code

 let userLayout = UICollectionViewFlowLayout()
let userController = UserController(collectionViewLayout: userLayout)
let navController = UINavigationController(rootViewController: userController)
navController.tabBarItem.image = UIImage(named: "loc-map-route")

Related

class UserController : UICollectionViewController, UICollectionViewDelegateFlowLayout
{
    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView?.backgroundColor = UIColor.green

    }
}

Environment

ios 10 swift 3 xcode 8

Thanks.

In your definition of createNavController your parameter controllerName is of type UICollectionViewController and that is not a function type so you cannot call it as a function, ie controllerName(...) .

If you replace

let viewController = controllerName(collectionViewLayout: layout)

with

let viewController = UserController(collectionViewLayout: layout)

from your working code, it compiles fine. Also, you don't need the controllerName parameter anymore. I don't quite understand what this is for anyway. Did you want to be able to specify the controller type ? Then you could do it like dan suggests (although this code requires a UICollectionViewController because you would be using init(collectionViewLayout:) ).

You could also pass an instance of the view controller you want embedded in the navigation controller like this:

private func createNavController(imageName: String, rootViewController: UIViewController) -> UINavigationController
{
           let navController = UINavigationController(rootViewController: rootViewController)
           navController.tabBarItem.image = UIImage(named: imageName)
           return navController
}

and call it like this:

let navController = createNavController(
    imageName: "loc-map-route",
    rootViewController: UserController(collectionViewLayout: UICollectionViewFlowLayout()))

This would indeed not require a UICollectionViewController because UINavigationController.init(rootViewController:) takes a UIViewController . It all depends on what you want to achieve.

Do you want something like this?

private func createNavController<T: UICollectionViewController>(imageName: String, _ controllerName: T.Type) -> UINavigationController {
    let layout = UICollectionViewFlowLayout()
    let viewController = controllerName.init(collectionViewLayout: layout)
    let navController = UINavigationController(rootViewController: viewController)
    navController.tabBarItem.image = UIImage(named: imageName)
    return navController
}

Then you can do: let nav = createNavController(imageName: "loc-map-route", UserCollectionController.self) and nav will have a UserCollectionController as its root.

I think that controllerName is an instance of UICollectionViewController, so it is an already initialized UICollectionViewController. It is not the name of the UICollectionViewController subclass. So if you just want to set the collectionViewLayout of that UICollectionViewController, I'd do:

private func createNavController(imageName: String, _ controllerName: UICollectionViewController) -> UINavigationController
{
    let layout = UICollectionViewFlowLayout()
    let viewController = controllerName.collectionViewLayout = layout
    let navController = UINavigationController(rootViewController: viewController)
    navController.tabBarItem.image = UIImage(named: imageName)

    return navController
}

The you would call it like this:

let navController = createNavController(imageName: "my_image", myCreatedUserController)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM