Cannot convert return expression of type '***' to return type '***'

Hey,

This is a part of my code:


SecondViewController.swift

import UIKit
class DemoViewController: ExpandingViewController {
    typealias ItemInfo = (imageName: String, title: String)
    fileprivate var cellsIsOpen = [Bool]()
    fileprivate let items: [ItemInfo] = [("item0", "Boston"), ("item1", "New York"), ("item2", "San Francisco"), ("item3", "Washington")]
    
    @IBOutlet var pageLabel: UILabel!
    
    }
extension DemoViewController{
    override func viewDidLoad() {
        itemSize = CGSize(width: 256, height: 460)
        super.viewDidLoad()
        
        registerCell()
        fillCellIsOpenArray()
        addGesture(to: collectionView!)
        configureNavBar()
    }
}
extension DemoViewController {
    
    fileprivate func registerCell() {
        
        let nib = UINib(nibName: String(describing: UICollectionViewCell.self), bundle: nil)
        collectionView?.register(nib, forCellWithReuseIdentifier: String(describing: UICollectionViewCell.self))
    }
    
    fileprivate func fillCellIsOpenArray() {
        cellsIsOpen = Array(repeating: false, count: items.count)
    }
    
    fileprivate func getViewController() -> ExpandingTableViewController {
        let storyboard = UIStoryboard(storyboard: .Main)
        let toViewController: DemoTableViewController = storyboard.instantiateViewController()
        
        return toViewController
    }
    
    fileprivate func configureNavBar() {
        navigationItem.leftBarButtonItem?.image = navigationItem.leftBarButtonItem?.image!.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
    }
}

/// MARK: Gesture
extension DemoViewController {
    
    fileprivate func addGesture(to view: UIView) {
        let upGesture = Init(UISwipeGestureRecognizer(target: self, action: #selector(DemoViewController.swipeHandler(_:)))) {
            $0.direction = .up
        }
        
        let downGesture = Init(UISwipeGestureRecognizer(target: self, action: #selector(DemoViewController.swipeHandler(_:)))) {
            $0.direction = .down
        }
        view.addGestureRecognizer(upGesture)
        view.addGestureRecognizer(downGesture)
    }
    
    @objc func swipeHandler(_ sender: UISwipeGestureRecognizer) {
        let indexPath = IndexPath(row: currentIndex, section: 0)
        guard let cell = collectionView?.cellForItem(at: indexPath) as? DemoCollectionViewCell else { return }
        // double swipe Up transition
        if cell.isOpened == true && sender.direction == .up {
            pushToViewController(getViewController())
            
            if let rightButton = navigationItem.rightBarButtonItem as? AnimatingBarButton {
                rightButton.animationSelected(true)
            }
        }
        
        let open = sender.direction == .up ? true : false
        cell.cellIsOpen(open)
        cellsIsOpen[indexPath.row] = cell.isOpened
    }
}

// MARK: UIScrollViewDelegate

extension DemoViewController {
    
    func scrollViewDidScroll(_: UIScrollView) {
        pageLabel.text = "\(currentIndex + 1)/\(items.count)"
    }
}

// MARK: UICollectionViewDataSource

extension DemoViewController {
    
    override func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        super.collectionView(collectionView, willDisplay: cell, forItemAt: indexPath)
        guard let cell = cell as? DemoCollectionViewCell else { return }
        
        let index = indexPath.row % items.count
        let info = items[index]
        cell.backgroundImageView?.image = UIImage(named: info.imageName)
        cell.customTitle.text = info.title
        cell.cellIsOpen(cellsIsOpen[index], animated: false)
    }
    
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) as? DemoCollectionViewCell
            , currentIndex == indexPath.row else { return }
        
        if cell.isOpened == false {
            cell.cellIsOpen(true)
        } else {
            pushToViewController(getViewController())
            
            if let rightButton = navigationItem.rightBarButtonItem as? AnimatingBarButton {
                rightButton.animationSelected(true)
            }
        }
    }
}

// MARK: UICollectionViewDataSource

extension DemoViewController {
    
    override func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int {
        return items.count
    }
    
    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        return collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: DemoCollectionViewCell.self), for: indexPath)
    }
}

TableViewController.swift

import UIKit

/// Base class for UITableViewcontroller which have back transition method
open class ExpandingTableViewController: UITableViewController {

    // MARK: Vars
  /// The height of the table view header, set before transition
    open var headerHeight: CGFloat = 236

    var transitionDriver: TransitionDriver?
}

// MARK: Helpers

extension ExpandingTableViewController {

    fileprivate func getScreen() -> UIImage? {
        let height = (headerHeight - tableView.contentOffset.y) < 0 ? 0 : (headerHeight - tableView.contentOffset.y)
        let backImageSize = CGSize(width: view.bounds.width, height: view.bounds.height - height + getTabBarHeight())
        let backImageOrigin = CGPoint(x: 0, y: height + tableView.contentOffset.y)
        return view.takeSnapshot(CGRect(origin: backImageOrigin, size: backImageSize))
    }

    fileprivate func getTabBarHeight() -> CGFloat {
        guard let navigationController = self.navigationController else {
            return 0
        }

        let insets = automaticallyAdjustsScrollViewInsets
        let tabBarHeight = insets == true ? navigationController.navigationBar.frame.size.height : 0
        let stausBarHeight = insets == true ? UIApplication.shared.statusBarFrame.size.height : 0
        return tabBarHeight + stausBarHeight
    }
}

// MARK: Methods

extension ExpandingTableViewController {

    /**
     Pops the top view controller from the navigation stack and updates the display with custom animation.
     */
    public func popTransitionAnimation() {
        guard let transitionDriver = self.transitionDriver else {
            return
        }

        let backImage = getScreen()
        var offset = tableView.contentOffset.y > headerHeight ? headerHeight : tableView.contentOffset.y

        offset += getTabBarHeight()

        transitionDriver.popTransitionAnimationContantOffset(offset, backImage: backImage)
        _ = navigationController?.popViewController(animated: false)
    }
}


There is an error in SecondViewController.swift at the line 37 :

return toViewController


And the error message is "Cannot convert return expression of type 'DemoTableViewController' to return type 'ExpandingTableViewController' "

What should I do to make it right?

Thanks.

Replies

You are not showing the definition of `DemoTableViewController`. How is it defined?

This's the definition:

DemoTableViewController.swift


import UIKit

class DemoTableViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }

Did you try changing:


    fileprivate func getViewController() -> ExpandingTableViewController {
        let storyboard = UIStoryboard(storyboard: .Main)
        let toViewController: DemoTableViewController = storyboard.instantiateViewController()
      
        return toViewController  as! ExpandingTableViewController
    }

or change


    fileprivate func getViewController() -> DemoTableViewController {
        let storyboard = UIStoryboard(storyboard: .Main)
        let toViewController: DemoTableViewController = storyboard.instantiateViewController()
      
        return toViewController  
    }

First I tried the former you suggested and there is a warning at the same line : " Cast from 'DemoTableViewController' to unrelated type 'ExpandingTableViewController' always fails "


Then I tried the later and there are 2 errors in SecondViewController.swift at line 65 and line 109 with error message : "Cannot convert value of type 'DemoTableViewController' to expected argument type 'ExpandingTableViewController' "

OK, I got confused between your 2 classes :

ExpandingViewController and ExpandingTableViewController


It is suprising that DemoTableViewController is a UIViewController and not UITableViewController.


Are you sure of it ?


If that's a mistake, correct it and tell if your original code works.

Then the reason is clear.


You declare your `toViewController` as of type `DemoTableViewController`.

Also you declare the return type of `getViewController()` as `ExpandingTableViewController`.


You cannot return an instance of `DemoTableViewController` which is not a subclass of `ExpandingTableViewController`.


Many things are not clear what you really want to do, but one possibility, you may need to declare your `DemoTableViewController` as a subclass of `ExpandingTableViewController`:

class DemoTableViewController: ExpandingTableViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
    
    //...
}