IT

클래스 유형을 함수 매개 변수로 전달하는 방법

lottoking 2020. 6. 27. 10:40
반응형

클래스 유형을 함수 매개 변수로 전달하는 방법


웹 서비스를 호출하고 JSON 응답을 다시 객체로 직렬화하는 일반 함수가 있습니다.

class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: AnyClass, completionHandler handler: ((T) -> ())) {

            /* Construct the URL, call the service and parse the response */
}

내가 달성하려는 것은이 Java 코드와 같습니다.

public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params,
                               final Class<T> classTypeToReturn) {
}
  • 내가 성취하려는 것에 대한 메소드 서명이 올바른가?
  • 더 구체적 AnyClass으로, 매개 변수 유형으로 지정 하는 것이 올바른 일입니까?
  • 메서드를 호출하면 MyObject.selfreturningClass 값으로 전달 되지만 컴파일 오류 "식의 유형 '()'을 'String'으로 변환 할 수 없습니다."
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/

}

편집하다:

나는 사용하여 시도 object_getClassholex에서 언급 한 바와 같이,하지만 지금은 얻을 :

오류 : " 'CityInfo.Type'유형이 'AnyObject'프로토콜을 준수하지 않습니다."

프로토콜을 준수하기 위해 무엇을해야합니까?

class CityInfo : NSObject {

    var cityName: String?
    var regionCode: String?
    var regionName: String?
}

당신은 잘못된 방법으로 접근하고있다 : 스위프트에, 오브젝티브 C는 달리, 클래스가 특정 유형이, 심지어 상속 계층 구조를 가지고 (즉, 경우에 클래스 B에서 상속 AB.Type로부터도 상속 A.Type) :

class A {}
class B: A {}
class C {}

// B inherits from A
let object: A = B()

// B.Type also inherits from A.Type
let type: A.Type = B.self

// Error: 'C' is not a subtype of 'A'
let type2: A.Type = C.self

당신은 사용하지 말아야하는 이유 AnyClass당신이 정말로 허용 할 않는 한, 어떤 클래스를. 이 경우 매개 변수와 클로저의 매개 변수 T.Type사이의 링크를 표시하므로 올바른 유형은 returningClass입니다.

실제로 대신에 AnyClass이를 사용하면 컴파일러가 메소드 호출에서 유형을 올바르게 유추 할 수 있습니다.

class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: T.Type, completionHandler handler: ((T) -> ())) {
    // The compiler correctly infers that T is the class of the instances of returningClass
    handler(returningClass())
}

지금의 인스턴스를 구성의 문제가있을 T전달할는 handler: 당신이 시도하고 실행 코드를 지금 컴파일러가 불평 할 경우 T와 작도하지 않습니다 (). 그리고 올바르게 : T특정 초기화 프로그램을 구현하도록 요구하려면 명시 적으로 제한해야합니다.

이것은 다음과 같은 프로토콜로 수행 할 수 있습니다.

protocol Initable {
    init()
}

class CityInfo : NSObject, Initable {
    var cityName: String?
    var regionCode: String?
    var regionName: String?

    // Nothing to change here, CityInfo already implements init()
}

그런 다음 일반 제약 조건을 invokeService에서 <T>변경하기 만하면 됩니다 <T: Initable>.

"표현식 '()'을 (를) '문자열'로 변환 할 수 없습니다"와 같은 이상한 오류가 발생하면 메서드 호출의 모든 인수를 자체 변수로 이동하는 것이 유용한 경우가 많습니다. 오류를 일으키는 코드를 좁히고 형식 유추 문제를 발견하는 데 도움이됩니다.

let service = "test"
let params = ["test" : "test"]
let returningClass = CityInfo.self

CastDAO.invokeService(service, withParams: params, returningClass: returningClass) { cityInfo in /*...*/

}

Now there are two possibilities: the error moves to one of the variables (which means that the wrong part is there) or you get a cryptic message like "Cannot convert the expression's type () to type ($T6) -> ($T6) -> $T5".

The cause of the latter error is that the compiler is not able to infer the types of what you wrote. In this case the problem is that T is only used in the parameter of the closure and the closure you passed doesn't indicate any particular type so the compiler doesn't know what type to infer. By changing the type of returningClass to include T you give the compiler a way to determine the generic parameter.


you can get the class of AnyObject via this way:

Swift 3.x

let myClass: AnyClass = type(of: self)

Swift 2.x

let myClass: AnyClass = object_getClass(self)

and you can pass it as paramater later, if you'd like.


I have a similar use case in swift5:

class PlistUtils {

    static let shared = PlistUtils()

    // write data
    func saveItem<T: Encodable>(url: URL, value: T) -> Bool{
        let encoder = PropertyListEncoder()
        do {
            let data = try encoder.encode(value)
            try data.write(to: url)
            return true
        }catch {
            print("encode error: \(error)")
            return false
        }
    }

    // read data

    func loadItem<T: Decodable>(url: URL, type: T.Type) -> Any?{
        if let data = try? Data(contentsOf: url) {
            let decoder = PropertyListDecoder()
            do {
                let result = try decoder.decode(type, from: data)
                return result
            }catch{
                print("items decode failed ")
                return nil
            }
        }
        return nil
    }

}


Use obj-getclass:

CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: obj-getclass(self)) { cityInfo in /*...*/

}

Assuming self is a city info object.

참고URL : https://stackoverflow.com/questions/24308975/how-to-pass-a-class-type-as-a-function-parameter

반응형