2017-02-08 14 views
6

Tôi rất vui khi thấy Swift 3 thực hiện #keyPath(), điều này sẽ loại bỏ lỗi chính tả và thực thi tại thời gian biên dịch mà đường dẫn chính thực sự tồn tại. Tốt hơn nhiều so với nhập chuỗi bằng tay.Tên "đặc tính" không phải là chuỗi được chuyển đến #keyPath() có được lưu độc lập không?

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) 

Các Swift docs list the type được thông qua vào #keyPath() như là một "tên tài sản".

"property name"

Tên thuộc tính phải là một tham chiếu đến một tài sản có sẵn trong thời gian chạy Objective-C. Tại thời gian biên dịch, biểu thức đường dẫn khóa được thay thế bằng một chuỗi ký tự.

Có thể lưu "tên thuộc tính" độc lập này không, sau đó chuyển đến #keyPath() để tạo chuỗi?

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

Có hỗ trợ nào để yêu cầu tên thuộc tính thuộc Loại cụ thể không?

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

Mục tiêu cuối cùng sẽ tương tác với API yêu cầu NSExpression cho đường dẫn chính. Tôi muốn viết các phương thức tiện lợi có một Tên thuộc tính hợp lệ làm tham số, chứ không phải là các chuỗi đường dẫn khóa ngẫu nhiên. Lý tưởng nhất, một tên thuộc tính được thực hiện bởi một loại cụ thể.

func doSomethingForSpecificTypeProperty(_ propertyName: MyObject.PropertyName) { 

    let keyPathString = #keyPath(propertyName) 

    let expression = NSExpression(forKeyPath: keyPathString) 

    // ... 
} 
+0

Swift 4 của [KeyPaths thông minh: Better Key-Value Mã hóa cho Swift] (https://github.com/apple/swift-evolution/blob/master/proposals/0161-key-paths.md) dường như thêm tùy chọn tốt hơn. Sẽ chấp nhận câu trả lời đó nếu có ai đó muốn viết nó trước khi tôi nhận được nó. – pkamb

+0

https://bugs.swift.org/browse/SR-5220 - "Hiển thị API để truy xuất biểu diễn chuỗi của KeyPath" – pkamb

+0

https://github.com/kishikawakatsumi/Kuery - "API truy vấn dữ liệu lõi an toàn loại sử dụng Smart KeyPaths của Swift 4 " – pkamb

Trả lời

4

Có vẻ như không thể.


Đây là mã của trình biên dịch để phân tích một biểu thức đường dẫn chính:

/// 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, keywordLoc, lParenLoc, names, 
            nameLocs, rParenLoc)); 
} 

Mã này đầu tiên tạo ra một danh sách các tên kỳ tách bên trong dấu ngoặc đơn, và sau đó nó cố gắng phân tích chúng như là một biểu . Nó chấp nhận một biểu thức và không phải dữ liệu của bất kỳ loại Swift nào; nó chấp nhận , không phải dữ liệu.

+0

Hy vọng rằng điều này sẽ được giới thiệu trong một phiên bản tương lai của Swift! – pkamb

1

Chỉ cần đưa ra câu hỏi tương tự và tìm thấy this article. Bạn có thể sử dụng KeyPath chung cho những mục đích

Mã ngắn cho điều này trong nhanh chóng 4 trông như thế này:

let getName = \Person.name 
print(p[keyPath: getName]) 

// or just this: 
print(p[keyPath: \Person.name]) 
Các vấn đề liên quan