2017-02-17 2 views
0

이상한 일반적인 행동을 보면 내 이해에서 뭔가 빠져 있다는 것을 알게됩니다.스위프트 (Swift) : 런타임시 일반 유형 유추

다음 메소드를 사용하여 JSON 응답을 루프 처리하고 일반 메소드를 호출합니다. User, CardEcard 모든 차례로

let props:[(label:String, type:IDObject.Type)] = [ 
    (label: "deletedUsers", type: User.self), 
    (label: "deletedCards", type: Card.self), 
    (label: "deletedECards", type: Ecard.self) 
] 

for prop in props { 
    if let ids = json[prop.label].arrayObject as? [Int], ids.count > 0 { 
     DataManager.shared.delete(prop.type, ids: ids) 
    } 
} 

func delete<T:IDObject>(_ type:T.Type, ids:[Int]) { 
    guard ids.count > 0 else { return } 
    if let objectsToDelete = objects(type, where: NSPredicate(format: "identifier IN %@", ids)) { 
     delete(objectsToDelete) 
    } 
} 

func delete<T:Object>(_ objects:Results<T>) { 
    guard objects.count > 0 else { return } 
    do { 
     let realm = try Realm() 
     try realm.write { 
      realm.delete(objects) 
     } 
    } catch { 
     print(error) 
    } 
} 

delete(_ type:T.Type, ids:[Int]) 기능은 제네릭 형식이 방법을 추론 할 수 Object (A 영역 클래스)에서 상속하는 IDObject에서 상속합니다.

그러나 for prop in props 루프의 래핑을 해제하면 예상대로 작동합니다.

if let userIds = json["deletedUsers"].arrayObject as? [Int], userIds.count > 0 { 
    DataManager.shared.delete(User.self, ids: userIds) 
} 

제네릭은 컴파일시에만 작동하며, 런타임시 동적으로 처리 할 수있는 방법이 있습니까?

+0

정확히 당신이 "무엇을 의미합니까 *은' delete 함수는 generic 형식을 이런 식으로 유추 할 수 없습니다 * "? 컴파일러 오류가 발생합니까? (만약 그렇다면 어디에서?)'DataManager.shared.delete (prop.type, ids : ids')에서 닫는 괄호를 놓치고 있습니다. 하나의 매개 변수로'delete'를 오버로드하지 않으면, 당신은 그것을 호출 할 수 없습니다. 단일 매개 변수 ('delete (objectsToDelete)'). 예상되는 동작과 실제 동작을 포함하여 [mcve]를 제공 할 수 있습니까? – Hamish

+0

@Hamish 전체 코드베이스가 매우 커서 공유 할 자유가 없습니다. 여기에 많은 부분을 수정했고 누락 된 닫는 괄호를 수정했습니다. delete는 실제로 오버로드되었습니다. delete (:) 메소드는'결과 '-'IDObject'가'Object'를 상속 받길 기대합니다. 내가 바라는 동작은 delete (objects :) 메쏘드에있다. objects.count == 0 – dmorrow

+0

전체 코드베이스를 공유 할 필요는 없으며 같은 문제를 재현하는 최소한의 독립적 인 예제 만이 존재한다. DataManager.shared.delete'는'delete (_ : ids :)'를 참조해야합니까?'objects (_ : where :)'는 무엇을 반환합니까? 심지어 같은 문제를 재현하는 함수를 모의해라.) 'ids'는 문제와 관련이 있습니까? (그렇지 않으면 제거하십시오). – Hamish

답변

1

제네릭은 컴파일 타임에 평가되며 단일 콘크리트 유형이 지정됩니다. 런타임에 타입 유추 같은 것은 없습니다.

나는 당신이 원하는 차 변화가 생각 :

func delete(_ type:IDObject.Type, ids:[Int]) { 

당신은 type에이 기능을 전문으로하고 싶지 않아, 당신은 단지 type를 전달하려는.

무엇이 objects(_:where:)가 반환하는지 명확하지 않아 사용자의 delete 메소드가 손상 될 수 있습니다. 당신은 덜 구체적해야 할 수 있습니다 : (.이 하위 유형에 대한 만병 통치약 아니다, 나는 objects(_:where:) 반환 정확히 Results<Object>가 있으리라 믿고있어)

func delete(_ objects:Results<Object>) { 

+0

I think * "type inference at runtime"이란 말은 [this] (http://stackoverflow.com/a/30945263/5175709)와 같은 의미입니다 ** 프로토콜은 정적 또는 동적 디스패치를 ​​선택할 수 있습니다. ** 그는 기본적으로 의미합니다. 정적 대 동적 전달. – Honey

+0

여기에 뭔가 빠져있을 수도 있지만'type' 매개 변수의 정적 유형을 변경하면 OP 코드의 런타임 동작이 변경됩니다 (실제로는'delete'를 호출 할 때를 고려합니다 (실제로'DataManager.shared .delete'),'T'는 이미'IDObject'로 추측됩니다. 또한 제네릭은 컴파일러 최적화로만 전문화되어 있습니다. – Hamish

+0

이미'IDObject'로 추측 될 수도 있지만, 독자가 더 많이 발생한다고 믿을 가능성이 있기 때문에 전문적으로 혼란 스럽습니다 (이 코드는 컴파일되지 않기 때문에 테스트하기가 어렵습니다). "전문화"는 함수의 고유 버전이 컴파일러에 의해 작성된다는 것을 의미하지는 않습니다. 'Array '은 컴파일러에 의해 어떻게 구현되는지에 관계없이'Int'에 대한'Array'의 특수화입니다. –