【问题标题】:Macros with return value有返回值的宏
【发布时间】:2016-03-22 17:03:47
【问题描述】:

我正在尝试在 Swift 中重现这种模式

#define mustBeKindOfClassFailedReturn(object, objectClass, ret) \
if(![object isKindOfClass:objectClass]) { \
NSLog(([NSString stringWithFormat:@"%@ must be kind of %@ class, current class is %@", object, NSStringFromClass(objectClass), NSStringFromClass([object class])])) \
return ret; }

这样使用

 - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                    layout:(UICollectionViewLayout*)collectionViewLayout
    insetForSectionAtIndex:(NSInteger)section {

mustNotBeNilFailedReturn(self.adapter, UIEdgeInsetsZero)
mustBeKindOfClassFailedReturn(self.adapter, [WBCollectionViewSectionAdapter class], UIEdgeInsetsZero)

有人知道解决这个问题的好方法吗?

编辑

我知道守卫,但使用守卫我必须重写很多代码,每次我必须重写我的子类中的一个方法,例如

/**
* mustOverride
*/
#define mustOverride \
{ NSLog(@"You must override this function") }

#define mustOverrideFailedReturn(ret) \
{ mustOverride \
return ret; }

编辑 2

我已经结束了解决方案,这是最佳解决方案吗?

func needOverride(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__) -> Bool {

    REVLogManager.SharedInstance.logErrorMessage("You must override this function", function: function, file: file, line: line, exception: nil, error: nil)

    return false

}

func doesObject(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__, matchingObject: AnyObject!, matchesClass matchingClass: AnyClass) -> Bool {

    guard matchingObject.isKindOfClass(matchingClass) else {

        let message = "\(matchingObject) must be kind of \(matchingClass) class, current class is \(matchingObject.dynamicType)"
        REVLogManager.SharedInstance.logErrorMessage(message, function: function, file: file, line: line, exception: nil, error: nil)

        return false

    }

    return true

}

我是这样调用方法的

public func actualScrollOffsetDistanceWithScrollView(scrollView: UIScrollView!) -> Float {

    guard needOverride() else { return 0.0 }
    return 0.0

}

guard doesObject(matchingObject: self, matchesClass: REVListSectionAdapter.classForCoder()) else { return }

【问题讨论】:

  • 什么是“ret”?
  • 它可以是任何东西:Float、Int、AnyObject、Bool、UIEdgeInsets 甚至 nil

标签: objective-c swift macros


【解决方案1】:

Swift 没有这种宏功能。

就实现目标而言。您所遵循的模式将使用guard 语句最正确地处理。包含保护语句的函数必须退出封闭范围(或陷阱),并且可以通过 return 退出。

有关控制流和提前退出控制的信息,请查看 Swift 文档

【讨论】:

    【解决方案2】:

    我的回答遵循 Swift 中使用的相同传统模式。您可以使用classForCoder,但我更喜欢dynamicType 进行类型检查。

    func mustBeKindOfClassFailedReturn(object: AnyObject, objectClass: AnyClass, returnVal: Any?) {
        if !object.isKindOfClass(objectClass) {
            print("\(object) must be kind of \(objectClass) class, current class is \(object.dynamicType)")
            return returnVal
        }
        return nil // or UIEdgeInsetsZero, or whatever
    }
    

    !(object is objectClass) 也可能会得到类似的结果,但在比较某些数字类型时会变得很棘手。见Swift type inference and type checking issue

    如果您知道自己处理的是 Objective-C 类型,也可以将 AnyObjectAny 替换为 NSObject。从您的评论看来,ret 可能是一个值类型,所以这就是我将其设为 Any 类型的原因。

    【讨论】:

    • 但是即使我的对象是正确的类,我也会返回“returnVal”,这对我来说不好
    • @Pwyll28 啊,我看错了你的宏,编辑了我的答案,如果类不匹配则返回 nil。
    • 除了重写 "if let" 或 "guard let" 之外,这还有什么作用吗?
    • @PEEJWEEJ 它保留了日志记录和传统风格。如果 OP 想要更多 Swift-y 代码,他们可以使用 if letguard
    • 我想如果你打算用 Swift 编写 Objective-C,那很好,但是应该编写好的 swift 代码 (IMO) 来隐式处理这些情况,或者理想情况下,这样编写它们根本不会发生。 (耶!):-)
    【解决方案3】:

    对于这类问题,Swift 有更好的解决方案,the guard statement。在这种情况下,只需将其放入您的方法中即可。

    guard let adapter = self.adapter as? WBCollectionViewSectionAdapter else {
    /* return value if the adapter is not setup properly. */
        return .Zero
    }
    /* continue with valid and correctly classed adapter */
    

    如果您正在寻找一种方法来处理子类,您可能需要考虑generics。它将允许您隐式类型安全,而无需重写子类中的逻辑。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多