简体   繁体   English

swift条件函数返回

[英]swift conditional function return

I would like to know how to manage conditional returns in swift. 我想知道如何在swift中管理条件返回。 For instance, I'm returning a custom UICollectionViewCell depending on which collectionview delegate is called: 例如,我正在返回一个自定义的UICollectionViewCell,具体取决于调用哪个collectionview委托:

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
      if (collectionView.isEqual(collectionView1)) {
         var cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell1", forIndexPath: indexPath) as Cell1
         return cell
      }
      else if (collectionView.isEqual(collectionView2)) {
        var cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell2", forIndexPath: indexPath) as Cell2
        return cell
      }
}

The compiler says "Missing return statement in a function expeted to return UICollectionViewCell", even in both cases I'm returning a cell. 编译器说“在函数中丢失返回语句以返回UICollectionViewCell”,即使在两种情况下我都返回一个单元格。

I solved it adding 我解决了这个问题

return UICollectionViewCell()

at the bottom of the function, but I don't think it's the correct way. 在函数的底部,但我认为这不是正确的方法。

I know I can declare the cell above the first 'if', modify it and return it at the end of the function outside the 'if', but then the 'dequeueReusableCellWithIdentifier' call hangs. 我知道我可以在第一个'if'之上声明单元格,修改它并在'if'之外的函数末尾返回它,然后'dequeueReusableCellWithIdentifier'调用挂起。

Thank you all. 谢谢你们。

To explain @MidhunMP's answer, right now your code is able to end without any return value. 要解释@ MidhunMP的答案,现在您的代码能够以没有任何返回值的方式结束。 For example look at this code, which is similar to yours: 例如,查看此代码,与您的代码类似:

func myFunc() -> Int {
    let myNumber = random() % 3
    if myNumber == 0 {
        return 0
    }
    else if myNumber == 1 {
        return 1
    }
}

What if myNumber is 2? 如果myNumber是2怎么办? The function ends without any return value, and this cannot happen. 函数结束时没有任何返回值,这不可能发生。

Either move the return statement to the end of the code, or add an else clause. 将return语句移动到代码的末尾,或者添加else子句。 Both ensure that your function will return a value under all circumstances. 两者都确保您的函数在所有情况下都会返回值。

You will need either: 您将需要:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    var cell = UICollectionViewCell()
    if (collectionView.isEqual(collectionView1)){
        cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell1", forIndexPath: indexPath) as Cell1
    } else if (collectionView.isEqual(collectionView2)){
        cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell2", forIndexPath: indexPath) as Cell2
    }
    return cell
}

or, 要么,

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    var cell = UICollectionViewCell()
    if (collectionView.isEqual(collectionView1)){
        cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell1", forIndexPath: indexPath) as Cell1
    return cell
    } else if (collectionView.isEqual(collectionView2)){
        cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell2", forIndexPath: indexPath) as Cell2
    return cell
    } else {
        return cell;
    }
}

However, use the first one because it is more elegant and it is easier to understand its meaning. 但是,使用第一个,因为它更优雅,更容易理解其含义。

The compiler cannot know that collectionView will always be collectionView1 or collectionView2 in your program and therefore it gives an error message. 编译器无法知道 collectionView将始终是程序中的collectionView1collectionView2 ,因此它会给出错误消息。

What you can do is to add an else case to make the compiler happy. 您可以做的是添加一个else案例以使编译器满意。 If everything does well, the else case will never be executed. 如果一切顺利,则永远不会执行else案例。 If there is a logic error in your program and both if conditions do not match, then (in the "Debug" configuration) the program will abort with an error message. 如果在你的程序中的逻辑错误和双方if条件不匹配,那么(在“调试”配置)程序将一个错误信息中止。

  if (collectionView.isEqual(collectionView1)) {
       let cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell1", forIndexPath: indexPath) as Cell1
       // set cell properties ... 
       return cell
  }
  else if (collectionView.isEqual(collectionView2)) {
      let cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell2", forIndexPath: indexPath) as Cell2
      // set cell properties ... 
      return cell
  }
  else {
      assertionFailure("unexpected collectionView")
      return UICollectionViewCell()
  }

Alternatively (and this is only a slight variant of the previous two answers), declare the cell as an implicitly unwrapped optional outside the if blocks: 或者(这只是前两个答案的略微变体),将cell声明为if块之外的隐式解包的可选项:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    var cell : UICollectionViewCell!
    if (collectionView.isEqual(collectionView1)){
        cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell1", forIndexPath: indexPath) as Cell1
        // set cell properties ... 
    } else if (collectionView.isEqual(collectionView2)){
        cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell2", forIndexPath: indexPath) as Cell2
        // set cell properties ... 
    }
    return cell
}

If none of the conditions match then nil is returned which also gives a runtime exception. 如果没有条件匹配,则返回nil ,这也会产生运行时异常。

First of all, to everyone answering, please not use var . 首先,请大家回答,请不要使用var Secondly, of course that is a correct error compiler-wise since the delegate method doesn't ensure that collectionView is either one of your defined ones, and requires that you return a valid cell so if you want to keep in the code both cases explicitly then you need to define a valid but never used case too. 其次,当然这是一个正确的编译器错误,因为委托方法不能确保collectionView是你定义的那个之一,并且要求你返回一个有效的单元格,所以如果你想在代码中保留两个明确的情况那么你需要定义一个有效但从未使用过的案例。 Also note that casting your cells to the proper subclass is useless here since they still are instantiated as the right class and still returned as a UICollectionViewCell as the delegate method signatures suggests. 还要注意,将您的单元格转换为正确的子类在这里是没用的,因为它们仍然被实例化为正确的类,并且仍然作为委托方法签名建议的UICollectionViewCell返回。

Here's a Swifter way of doing it: 这是一种更快捷的方式:

/// define this in any .swift file included in your project
func ~=<T: AnyObject>(lhs: T, rhs: T) -> Bool {
    return lhs === rhs
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let reuseIdentifier = cellReuseIdentifierForCollectionView(collectionView)
    return epgCollectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath)
}

private func cellReuseIdentifierForCollectionView(collectionView: UICollectionView) -> String {
    switch collectionView {
    case collectionView1:
        return "Cell1"
    case collectionView2:
        return "Cell2"
    default:
        return "" // this never happens but is still a bit of a code smell
    }
}

Since you need to return a UICollectionViewCell , it would be better if you create a single var for that and return it (I'm not a fan of writing multiple return statement in a method) So you can change it to something like: 因为你需要返回一个UICollectionViewCell ,如果为它创建一个var并返回它会更好(我不是在方法中编写多个return语句的粉丝)所以你可以将它改为:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
      var cell = UICollectionViewCell()
      if (collectionView.isEqual(collectionView1))
      {
         cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell1", forIndexPath: indexPath) as Cell1
      }
      else if (collectionView.isEqual(collectionView2))
      {
         cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell2", forIndexPath: indexPath) as Cell2
      }
      return cell
}

I find out the solution! 我找到了解决方案! More easy than it seems. 比看起来更容易。 Only must replace the "else if" by an "else": 只能用“else”替换“else if”:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
  if (collectionView.isEqual(collectionView1)) {
     var cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell1", forIndexPath: indexPath) as Cell1
     return cell
  }
  else (collectionView.isEqual(collectionView2)) {
    var cell = self.epgCollectionView.dequeueReusableCellWithReuseIdentifier("Cell2", forIndexPath: indexPath) as Cell2
    return cell
  }

} }

It works now. 它现在有效。 Thank you all guys! 谢谢大家!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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