2016-07-11 2 views
1

상속 한 웹 API 프레임 워크에 오류 처리 기능을 추가하고 있습니다. 현재는 강제 캐스팅을 많이 사용하기 때문에 데이터가 예상과 일치하지 않는 순간 충돌이 발생합니다.Swift에서 일반 유형 검사 기능을 만들 수 있습니까?

as!의 모든 용도를 유형을 확인하고 실패시 예외 (자세한 설명 포함)를 던지는 기능으로 바꾸고 싶습니다.

func checkType<T>(type: AnyClass, value: T?, name: String) throws -> T { 
    guard let value = value else { 
     let message = "[\(name)] Expected \(type), but value was nil" 
     throw PlaidsterError.InvalidType(message) 
    } 

    guard value.dynamicType.self == type else { 
     let message = "[\(name)] Expected \(type), but it was an \(value.dynamicType.self) with value: \(value)" 
     throw PlaidsterError.InvalidType(message) 
    } 

    return value 
} 

그러나 이것은 여러 문제가있다 :

이것은 내가 지금까지 들어 왔 것입니다. 그것은 단지 객체 유형을 취할 수 있습니다. 클래스가 정확히 일치하지 않으면 실패합니다 (예를 들어 NSString은 실제로 __NSCFString이기 때문에 실패합니다). 어떤 유형의 String, Int, Double에서도 작동하지 않습니다 ...

첫 번째 문제는 Any 값 유형에 대해 AnyClass의 동의어를 찾을 수 없습니다. 또한 type은 유형이 아니기 때문에 value.dynamicType.self is type과 같은 것을 수행 할 수없는 것으로 보입니다.


내가하려는 일을 할 수 있습니까? 이 종류의 유형 검사를 수행하는 좋은 방법이 파싱 코드 전체에 흩어져있는 상용구 코드없이 수행 할 수 있습니까? 당신은 다른 제네릭 형식 매개 변수를 다음처럼 작성할 수 있습니다

public struct PlaidCategory { 

    // MARK: Properties 
    public let id: String 
    public let hierarchy: [String] 
    public let type: String 

    // MARK: Initialization 
    public init(category: [String: Any]) throws { 
     id = try checkType(String.self, value: category["id"], name: "id") 
     hierarchy = try checkType([String].self, value: category["hierarchy"], name: "hierarchy") 
     type = try checkType(String.self, value: category["type"], name: "type") 
} 

}

+0

:

do { let n: Any = "x" let t: Int = try checkType(n, name: "n") print(t) } catch let error { print(error) //->InvalidType("[n] Expected Int, but it was an String with value: x") } 

나 :

func checkType<T, U>(value: T?, name: String) throws -> U { guard let value = value else { let message = "[\(name)] Expected \(U.self), but value was nil" throw PlaidsterError.InvalidType(message) } guard let result = value as? U else { let message = "[\(name)] Expected \(U.self), but it was an \(value.dynamicType) with value: \(value)" throw PlaidsterError.InvalidType(message) } return result } 

그리고로 사용 재미있는 "github swift json". SwiftyJSON, 광택 등. – Mattias

답변

3

:

내 목표는이 또는 간단하게 뭔가를 얻을 수 있습니다.

func checkType<T, U>(type: U.Type, value: T?, name: String) throws -> U { 
    guard let value = value else { 
     let message = "[\(name)] Expected \(type), but value was nil" 
     throw PlaidsterError.InvalidType(message) 
    } 

    guard let result = value as? U else { 
     let message = "[\(name)] Expected \(type), but it was an \(value.dynamicType) with value: \(value)" 
     throw PlaidsterError.InvalidType(message) 
    } 

    return result 
} 

그리고로 사용 :

do { 
    let n: Any = 3 
    let t = try checkType(Int.self, value: n, name: "n") 
    print(t) //->3 
} catch let error { 
    print(error) 
} 
do { 
    let n: Any = "x" 
    let t = try checkType(Int.self, value: n, name: "n") 
    print(t) 
} catch let error { 
    print(error) //->InvalidType("[n] Expected Int, but it was an _NSContiguousString with value: x") 
} 

나는 이것이 당신의 PlaidCategory.init(category:) 작동 희망하지만, 테스트하지.


하나 더. 반환 유형을 추측 할 수있는 경우에만 사용하면 type 매개 변수를 전달할 필요가 없습니다. 난 당신이 GitHub의에 수많은 신속한 JSON 파서 중 하나에서 봐 제안 당신이 뭔가를 찾을 수 있는지

public struct PlaidCategory { 

    // MARK: Properties 
    public let id: String 
    public let hierarchy: [String] 
    public let type: String 

    // MARK: Initialization 
    public init(category: [String: Any]) throws { 
     id = try checkType(category["id"], name: "id") 
     hierarchy = try checkType(category["hierarchy"], name: "hierarchy") 
     type = try checkType(category["type"], name: "type") 
    } 
} 
+0

고마워,이게 완벽 해! 내가 타입에 대한 일반적인 생각도하지 않았다는 것을 믿을 수 없다! 두 번째 대답은 아름답게 작동하며 (놀이터에서 테스트 됨) 더욱 간결합니다. –

+0

또한 JSON을 파싱하기 때문에 독점적으로 값을 가져 오기 때문에 두 번째 편의 함수를 추가하여 이름을 두 번 입력 할 필요가 없어졌습니다 :'func checkType (dictionary : Dictionary , name : String) throws -> U {값 = 사전 [이름]; 리턴 try checkType (value, name : name)}' –