클래스 유형을 함수 매개 변수로 전달하는 방법
나는 웹 서비스를 호출하고 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 */
}
제가 달성하고자 하는 것은 이 자바 코드와 동등한 것입니다.
public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params,
final Class<T> classTypeToReturn) {
}
- 수행하려는 작업에 대한 메서드 서명이 정확합니까?
- 더 구체적으로 , 는 보구체으로, 는다같지니다합정이를 지정하는 입니다.
AnyClass매개 변수로 올바른 작업을 입력하십시오. - 메소드를 부를 때, 저는 통과합니다.
MyObject.self반환되는 Class 값으로, 그러나 컴파일 오류가 발생합니다. "식의 유형 '(")을 유형 'String'으로 변환할 수 없습니다."
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/
}
편집:
사용해 보았습니다.object_getClass홀렉스가 말한 것처럼, 하지만 이제 나는 이해합니다.
오류: "'CityInfo'를 입력합니다.Type'이(가) 'AnyObject' 프로토콜과 맞지 않습니다."
프로토콜을 준수하려면 무엇을 해야 합니까?
class CityInfo : NSObject {
var cityName: String?
var regionCode: String?
var regionName: String?
}
에서는 Objective-C와상속 계층( 방접고근있습하니다로식으된잘못▁class▁(that있▁you다니습▁have▁hierarchyance▁an▁have▁inherit접고방하근식된으로▁swift▁classes,▁types잘▁even▁and못▁specific▁objective)을 가지고 있습니다. Swift에서는 Objective-C와 달리 클래스가 특정 유형을 가지며 상속 계층(즉, 클래스인 경우)도 있습니다.B는 에상됨속서의 상속을 받습니다.A,그리고나서B.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 /*...*/
}
두 가능성이 . 중 할 수 "와같은 됩니다. 오류가 변수 중 하나로 이동하거나(잘못된 부분이 있음을 의미) "식의 유형을 변환할 수 없습니다."와 같은 암호화된 메시지가 표시됩니다.()타이핑하는($T6) -> ($T6) -> $T5".
후자의 오류의 원인은 컴파일러가 당신이 쓴 것의 유형을 추론할 수 없기 때문입니다.이 경우 문제는T마감의 매개 변수에만 사용되며 전달한 마감은 특정 유형을 나타내지 않으므로 컴파일러는 어떤 유형을 추론해야 할지 알 수 없습니다.의 유형을 변경하여returningClass포함하는T컴파일러에 제네릭 매개 변수를 결정하는 방법을 제공합니다.
당신은 의 수업을 받을 수 있습니다.AnyObject이 방법을 통해:
스위프트 3.x
let myClass: AnyClass = type(of: self)
스위프트 2.x
let myClass: AnyClass = object_getClass(self)
나중에 매개 변수로 전달할 수 있습니다.
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
}
}
여기에 있는 각 코드를 swift 파일에 복사하여 붙여넣기만 하면 됩니다.
다른 이름으로 저장: APICaller.swift
import Foundation
struct APICaller
{
public static func get<T: Decodable>(url: String, receiveModel: T.Type, completion:@escaping (Decodable) -> ())
{
send(url: url, json: nil, receiveModel: receiveModel, completion: completion, httpMethod: "GET")
}
public static func post<T: Decodable>(url: String, json: [String: Any]?, receiveModel: T.Type, completion:@escaping (Decodable) -> ())
{
send(url: url, json: nil, receiveModel: receiveModel, completion: completion, httpMethod: "POST")
}
public static func delete<T: Decodable>(url: String, json: [String: Any]?, receiveModel: T.Type, completion:@escaping (Decodable) -> ())
{
send(url: url, json: nil, receiveModel: receiveModel, completion: completion, httpMethod: "DELETE")
}
private static func send<T: Decodable>(url: String, json: [String: Any]?, receiveModel: T.Type, completion:@escaping (Decodable) -> (), httpMethod: String)
{
// create post request
let urlURL: URL = URL(string: url)!
var httpRequest: URLRequest = URLRequest(url: urlURL)
httpRequest.httpMethod = httpMethod
if(json != nil)
{
// serialize map of strings to json object
let jsonData: Data = try! JSONSerialization.data(withJSONObject: json!)
// insert json data to the request
httpRequest.httpBody = jsonData
httpRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
}
// create an asynchronus task to post the request
let task = URLSession.shared.dataTask(with: httpRequest)
{ jsonData, response, error in
// on callback parse the json into the receiving model object
let receivedModelFilled: Decodable = Bundle.main.decode(receiveModel, from: jsonData!)
// cal the user callback with the constructed object from json
DispatchQueue.main.async {
completion(receivedModelFilled)
}
}
task.resume()
}
}
다음으로 저장:테스트 서비스.swift
import Foundation
struct TestService: Codable
{
let test: String
}
그러면 다음과 같이 사용할 수 있습니다.
let urlString: String = "http://localhost/testService" <--- replace with your actual service url
// call the API in post request
APICaller.post(url: urlString, json: ["test": "test"], receiveModel: TestService.self, completion: { testReponse in
// when response is received - do something with it in this callback
let testService: TestService = testReponse as! TestService
print("testService: \(testService)")
})
팁: 저는 온라인 서비스를 사용하여 제 JSON을 신속한 파일로 변환하기 때문에 제가 남은 것은 전화를 쓰고 응답을 처리하는 것입니다. 저는 이것을 사용합니다: https://app.quicktype.io 하지만 당신은 당신이 선호하는 것을 검색할 수 있습니다.
스위프트 5
정확히 같은 상황은 아니지만, 저도 비슷한 문제를 겪고 있었습니다.결국 도움이 된 것은 다음과 같습니다.
func myFunction(_ myType: AnyClass)
{
switch myType
{
case is MyCustomClass.Type:
//...
break
case is MyCustomClassTwo.Type:
//...
break
default: break
}
}
그런 다음 이 클래스를 다음과 같은 클래스의 인스턴스 내에서 호출할 수 있습니다.
myFunction(type(of: self))
이것이 저와 같은 상황에 있는 누군가에게 도움이 되기를 바랍니다.
최근에 UINavigation Controller를 하위 보기 버튼을 제외한 모든 항목에서 볼 수 없도록 만드는 방법을 찾고 있었습니다.사용자 지정 탐색 컨트롤러에 넣었습니다.
// MARK:- UINavigationBar Override
private extension UINavigationBar {
override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
// Make the navigation bar ignore interactions unless with a subview button
return self.point(inside: point, with: event, type: UIButton.self)
}
}
// MARK:- Button finding hit test
private extension UIView {
func point<T: UIView>(inside point: CGPoint, with event: UIEvent?, type: T.Type) -> Bool {
guard self.bounds.contains(point) else { return false }
if subviews.contains(where: { $0.point(inside: convert(point, to: $0), with: event, type: type) }) {
return true
}
return self is T
}
}
호출하기 전에 점이 변환되므로 프레임 대신 경계를 사용하는 것을 잊지 마십시오.
사용:
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: obj-getclass(self)) { cityInfo in /*...*/
}
자신을 도시 정보 객체로 가정합니다.
언급URL : https://stackoverflow.com/questions/24308975/how-to-pass-a-class-type-as-a-function-parameter
'programing' 카테고리의 다른 글
| WPF 백그라운드 작업자 사용 방법 (0) | 2023.05.27 |
|---|---|
| Mongodb 통합 프레임워크:$group은 인덱스를 사용합니까? (0) | 2023.05.27 |
| Ruby 배열을 X 요소의 일부로 분할(청크)하는 방법은 무엇입니까? (0) | 2023.05.27 |
| npm은 패키지에 종속성별로 개인 github 저장소를 설치합니다.제이손 (0) | 2023.05.27 |
| Mongoose에서 _id to db 문서를 설정하는 방법? (0) | 2023.05.27 |