swift – 传递给#keyPath()的非字符串“属性名称”可以独立保存吗?

前端之家收集整理的这篇文章主要介绍了swift – 传递给#keyPath()的非字符串“属性名称”可以独立保存吗?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我很高兴找到 Swift 3的#keyPath()实现,这将消除拼写错误并在编译时强制执行密钥路径.比手动键入字符串要好得多.

https://github.com/apple/swift-evolution/blob/master/proposals/0062-objc-keypaths.md

class MyObject {
    @objc var myString: String = "default"
}

// Works great
let keyPathString = #keyPath(MyObject.myString)

Swift docs list the type作为“属性名称”传递给#keyPath().

"property name"

The property name must be a reference to a property that is available in the Objective-C runtime. At compile time,the key-path expression is replaced by a string literal.

可以独立保存这个“属性名称”,然后传递给#keyPath()来创建一个String吗?

let propertyName = MyObject.myString // error. How do I save?
let string = #keyPath(propertyName)

是否支持要求属于特定类型的属性名称

// something like this
let typedPropertyName: MyObject.PropertyName = myString // error
let string = #keyPath(typedPropertyName)

最终目标将与需要NSExpression作为密钥路径的API进行交互.我想编写方便的方法,将有效的属性名称作为参数,而不是随机密钥路径字符串.理想情况下,由特定类型实现的属性名称.

func doSomethingForSpecificTypeProperty(_ propertyName: MyObject.PropertyName) {

    let keyPathString = #keyPath(propertyName)

    let expression = NSExpression(forKeyPath: keyPathString)

    // ...
}
它看起来不可能.

这是解析密钥路径表达式的编译器代码

///   expr-keypath:
///     '#keyPath' '(' unqualified-name ('.' unqualified-name) * ')'
///
ParserResult<Expr> Parser::parseExprKeyPath() {
  // Consume '#keyPath'.
  SourceLoc keywordLoc = consumeToken(tok::pound_keyPath);

  // Parse the leading '('.
  if (!Tok.is(tok::l_paren)) {
    diagnose(Tok,diag::expr_keypath_expected_lparen);
    return makeParserError();
  }
  SourceLoc lParenLoc = consumeToken(tok::l_paren);

  // Handle code completion.
  SmallVector<Identifier,4> names;
  SmallVector<SourceLoc,4> nameLocs;
  auto handleCodeCompletion = [&](bool hasDot) -> ParserResult<Expr> {
    ObjCKeyPathExpr *expr = nullptr;
    if (!names.empty()) {
      expr = ObjCKeyPathExpr::create(Context,keywordLoc,lParenLoc,names,nameLocs,Tok.getLoc());
    }

    if (CodeCompletion)
      CodeCompletion->completeExprKeyPath(expr,hasDot);

    // Eat the code completion token because we handled it.
    consumeToken(tok::code_complete);
    return makeParserCodeCompletionResult(expr);
  };

  // Parse the sequence of unqualified-names.
  ParserStatus status;
  while (true) {
    // Handle code completion.
    if (Tok.is(tok::code_complete))
      return handleCodeCompletion(!names.empty());

    // Parse the next name.
    DeclNameLoc nameLoc;
    bool afterDot = !names.empty();
    auto name = parseUnqualifiedDeclName(
                  afterDot,nameLoc,diag::expr_keypath_expected_property_or_type);
    if (!name) {
      status.setIsParseError();
      break;
    }

    // Cannot use compound names here.
    if (name.isCompoundName()) {
      diagnose(nameLoc.getBaseNameLoc(),diag::expr_keypath_compound_name,name)
        .fixItReplace(nameLoc.getSourceRange(),name.getBaseName().str());
    }

    // Record the name we parsed.
    names.push_back(name.getBaseName());
    nameLocs.push_back(nameLoc.getBaseNameLoc());

    // Handle code completion.
    if (Tok.is(tok::code_complete))
      return handleCodeCompletion(false);

    // Parse the next period to continue the path.
    if (consumeIf(tok::period))
      continue;

    break;
  }

  // Parse the closing ')'.
  SourceLoc rParenLoc;
  if (status.isError()) {
    skipUntilDeclStmtRBrace(tok::r_paren);
    if (Tok.is(tok::r_paren))
      rParenLoc = consumeToken();
    else
      rParenLoc = PrevIoUsLoc;
  } else {
    parseMatchingToken(tok::r_paren,rParenLoc,diag::expr_keypath_expected_rparen,lParenLoc);
  }

  // If we cannot build a useful expression,just return an error
  // expression.
  if (names.empty() || status.isError()) {
    return makeParserResult<Expr>(
             new (Context) ErrorExpr(SourceRange(keywordLoc,rParenLoc)));
  }

  // We're done: create the key-path expression.
  return makeParserResult<Expr>(
           ObjCKeyPathExpr::create(Context,rParenLoc));
}

代码首先在括号内创建一个以句点分隔的名称列表,然后尝试将它们解析为表达式.它接受表达式而不是任何Swift类型的数据;它接受代码,而不是数据.

原文链接:/swift/319051.html

猜你在找的Swift相关文章