Swift에서 객체가 주어진 유형인지 확인


267

구성된 배열이 AnyObject있습니다. 반복하고 배열 인스턴스 인 모든 요소를 ​​찾고 싶습니다.

Swift에서 객체가 주어진 유형인지 어떻게 확인합니까?


귀하의 질문은 주어진 객체의 유형을 찾는 것에 대해 묻지 만 객체가 주어진 유형인지 여부를 확인할 수있는 답변을 수락했습니다. 구체적으로 질문을 수정하시기 바랍니다. 그렇지 않으면 많은 독자들이 귀하가 수락 한 답변에 불만을 갖게됩니다. (다른 모든 답변은 비슷하므로 운 좋게도 질문을 좁혀서 무효화하는 것에 대해 걱정할 필요가 없습니다.)
Jeremy Banks

이 질문을 stackoverflow.com/q/24093433 에서 명확하게하기 위해 편집했습니다 . 그것들은 유용하고 비슷한 질문이지만, 대답은 매우 명확하므로 분리하여 유지하는 것이 유용합니다.
Jeremy Banks

답변:


304

특정 유형을 확인하려면 다음을 수행하십시오.

if let stringArray = obj as? [String] {
    // obj is a string array. Do something with stringArray
}
else {
    // obj is not a string array
}

"as!"를 사용할 수 있습니다 obj유형이 아닌 경우 런타임 오류가 발생합니다.[String]

let stringArray = obj as! [String]

한 번에 하나의 요소를 확인할 수도 있습니다.

let items : [Any] = ["Hello", "World"]
for obj in items {
   if let str = obj as? String {
      // obj is a String. Do something with str
   }
   else {
      // obj is not a String
   }
}

(가) 왜 그에만 런타임 오류가 아니라 컴파일시 에러를 슬로우 ?존재하지 않습니다. 그것은 같은 소리 as?결합 될 때 런타임 검사를 수행합니다. as없이 사용하기에 적절한시기는 언제 ?입니까? 미리 감사드립니다.
Unheilig

당신은 사용해야 @Unheilig as를 빼고 ?프로그램이 개체가 그렇지 않은 경우 프로그램이 즉시 정지 때문에 해당 유형의없는 복구 할 수있는 방법이없는 경우. 를 사용 ?if문은 프로그램을 계속 할 수 있습니다.
drewag

답변 주셔서 감사합니다. 내가 틀렸다면 바로 잡아라 : ?이 경우에 if를 사용하면 if 절에 그렇지 않으면 else 절에 대해 "일반"유형 검사를 수행 할 것이라고 생각했다 . 포함하지 않는 ?당신이 런타임 오류 원인을 지적를 입력하지 않을 것이라고 다른 등. 다시 감사합니다.
Unheilig

@ Unheilig 죄송합니다, 당신이 말하는 / 질문을 이해하지 못합니다. 이 ?경우 할당이 반환 nil되어 if 문이 반환 false되어 else 문으로 넘어 갑니다 . 그러나, 나는 그 설명이 이해하는 데 도움이,하지만 생각 if let실제로 컴파일러 특별한 경우이다
drewag

1
@Unheilig 맞습니다. 로컬 범위에있는 동안 값을 수정하려면 var를 사용할 수 있습니다 (이 변경 사항은 범위 외부에 영향을 미치지 않습니다)
drewag

202

에서 스위프트 2.2-5 당신이 지금 할 수있는 :

if object is String
{
}

그런 다음 배열을 필터링하십시오.

let filteredArray = originalArray.filter({ $0 is Array })

확인할 여러 유형이있는 경우 :

    switch object
    {
    case is String:
        ...

    case is OtherClass:
        ...

    default:
        ...
    }

이 솔루션은 짧은,하지만 단점이있다 : 당신은 사용할 수 없습니다 objectA와 String와 함께있는 동안, (스위프트 2 이상) 괄호 안에 let솔루션 당신이 그것을 할 수 있습니다.
Ferran Maylinch

@FerranMaylinch object블록에서 사용하는 것이 좋기 때문에 무슨 뜻인지 이해하지 못합니다 .
의미 문제

@ meaning-matters 예를 들어 object.uppercaseString변수의 유형이 해당 유형으로 캐스트되지 않기 때문에 수행 할 수 없습니다 . 변수 (변수로 표시된)가String
Ferran Maylinch입니다

확인중인 수업 유형이 임의적이라면 어떻게 할 수 있습니까? 변수 만있는 경우 클래스 유형을 가져와야합니까?
Alex Zavatone

152

객체 주어진 유형의 하위 유형 인지 만 알고 싶다면 더 간단한 방법이 있습니다.

class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}

func area (shape: Shape) -> Double {
  if shape is Circle { ... }
  else if shape is Rectangle { ... }
}

“유형 검사 연산자 (is)를 사용하여 인스턴스가 특정 하위 클래스 유형인지 확인합니다. 유형 검사 연산자는 인스턴스가 해당 서브 클래스 유형이면 true를 반환하고 그렇지 않으면 false를 반환합니다.” 발췌 : Apple Inc.“Swift Programming Language.” iBooks .

위의 '특정 서브 클래스 유형의'이라는 문구가 중요합니다. 컴파일러에서 해당 값 을 ( 및 수퍼 클래스) 로 선언 하기 때문에 is Circle및 의 사용 is Rectangle이 허용됩니다 .shapeShapeCircleRectangle

기본 유형을 사용하는 경우 수퍼 클래스는입니다 Any. 예를 들면 다음과 같습니다.

 21> func test (obj:Any) -> String {
 22.     if obj is Int { return "Int" }
 23.     else if obj is String { return "String" }
 24.     else { return "Any" }
 25. } 
 ...  
 30> test (1)
$R16: String = "Int"
 31> test ("abc")
$R17: String = "String"
 32> test (nil)
$R18: String = "Any"

2
배열에 기본 유형을 저장했거나 배열이 기본 유형 중 하나 인 경우 is에도 여전히 작동합니까? 감사.
Unheilig

objectas 을 선언하면 작동합니다 Any. 예제로 업데이트되었습니다.
GoZoner 2018 년

답변 감사합니다. 유망 해 보인다. 내 유일한 의심은 아래의 대답에 따르면,에서 상속되지 않았기 AnyObject때문에 왜곡 된 것처럼 보입니다 . 다른 경우 , 이것은 실제로 훌륭한 해결책이 될 것입니다. 감사. AnyObjectNSObjectAny
Unheilig

21

두 가지 방법이 있습니다.

if let thisShape = aShape as? Square 

또는:

aShape.isKindOfClass(Square)

자세한 예는 다음과 같습니다.

class Shape { }
class Square: Shape { } 
class Circle: Shape { }

var aShape = Shape()
aShape = Square()

if let thisShape = aShape as? Square {
    println("Its a square")
} else {
    println("Its not a square")
}

if aShape.isKindOfClass(Square) {
    println("Its a square")
} else {
    println("Its not a square")
}

편집 : 3 지금 :

let myShape = Shape()
if myShape is Shape {
    print("yes it is")
}

1
isKindOfClassNSObject프로토콜 의 방법입니다 . 그것은 그것을 채택하는 클래스 (NSObject에서 내려 오는 모든 클래스와 그것을 명시 적으로 채택하는 사용자 정의 Swift 클래스)에서만 작동해야합니다.
Nicolas Miari


9

drawTriangle 이 UIView의 인스턴스라고 가정합니다 drawTriangle 이 UITableView 유형인지 확인하려면 다음을 수행하십시오.

에서 스위프트 3 ,

if drawTriangle is UITableView{
    // in deed drawTriangle is UIView
    // do something here...
} else{
    // do something here...
}

이것은 스스로 정의한 클래스에도 사용될 수 있습니다. 이를 사용하여 뷰의 하위 뷰를 확인할 수 있습니다.


5

이 작업을 위해 특별히 내장 된 기능을 사용하지 않는 이유는 무엇입니까?

let myArray: [Any] = ["easy", "as", "that"]
let type = type(of: myArray)

Result: "Array<Any>"

type () 함수는 간단합니다
:)

5

이것에 대해 경고하십시오 :

var string = "Hello" as NSString
var obj1:AnyObject = string
var obj2:NSObject = string

print(obj1 is NSString)
print(obj2 is NSString)
print(obj1 is String)
print(obj2 is String) 

마지막 네 줄 모두가 true를 반환합니다.

var r1:CGRect = CGRect()
print(r1 is String)

... 물론 "거짓"을 인쇄하지만 CGRect에서 문자열로 캐스트에 실패했다는 경고가 표시됩니다. 따라서 일부 유형은 연결되어 있으며 'is'키워드는 암시 적 캐스트를 호출합니다.

다음 중 하나를 사용하는 것이 좋습니다.

myObject.isKind(of: MyClass.self)) 
myObject.isMember(of: MyClass.self))

2

사용되지 않은 정의 된 값 (일부 someVariable ...)으로 인해 경고를받지 않고 클래스를 확인하려는 경우 let 항목을 부울로 간단히 바꿀 수 있습니다.

if (yourObject as? ClassToCompareWith) != nil {
   // do what you have to do
}
else {
   // do something else
}

Xcode는 let 길을 사용하고 정의 된 값을 사용하지 않을 때 이것을 제안했습니다.


2

이 같은 것을 사용하지 않는 이유

fileprivate enum types {
    case typeString
    case typeInt
    case typeDouble
    case typeUnknown
}

fileprivate func typeOfAny(variable: Any) -> types {
    if variable is String {return types.typeString}
    if variable is Int {return types.typeInt}
    if variable is Double {return types.typeDouble}
    return types.typeUnknown
}

스위프트 3에서.


2

Swift 4.2, 제 경우에는 isKind 함수를 사용합니다.

isKind (of :) 수신자가 지정된 클래스의 인스턴스인지 또는 해당 클래스에서 상속 된 클래스의 인스턴스인지를 나타내는 부울 값을 리턴합니다.

  let items : [AnyObject] = ["A", "B" , ... ]
  for obj in items {
    if(obj.isKind(of: NSString.self)){
      print("String")
    }
  }

더 읽기 https://developer.apple.com/documentation/objectivec/nsobjectprotocol/1418511-iskind


1
그것은 스위프트가 아닙니다. Cocoa이며 Objective C에서 작동하는 곳에서만 작동합니다.
matt

1

myObject as? String이 아닌 nil경우를 반환 합니다 . 그렇지 않으면을 반환 하므로으로 문자열 자체에 액세스 하거나 안전하게 캐스트 할 수 있습니다.myObjectStringString?myObject!myObject! as String


1

스위프트 3 :

class Shape {}
class Circle : Shape {}
class Rectangle : Shape {}

if aShape.isKind(of: Circle.self) {
}

1

받아 들여진 대답과 다른 것들을 기반으로 완전성을 기하기 위해 :

let items : [Any] = ["Hello", "World", 1]

for obj in items where obj is String {
   // obj is a String. Do something with str
}

그러나 당신은 또한 할 수 있습니다 ( compactMap또한 값을 "매핑" filter) :

items.compactMap { $0 as? String }.forEach{ /* do something with $0 */ ) }

그리고 다음을 사용하는 버전 switch:

for obj in items {
    switch (obj) {
        case is Int:
           // it's an integer
        case let stringObj as String:
           // you can do something with stringObj which is a String
        default:
           print("\(type(of: obj))") // get the type
    }
}

그러나 배열 (예 :)인지 확인하기 위해 질문을 고집하십시오 [String].

let items : [Any] = ["Hello", "World", 1, ["Hello", "World", "of", "Arrays"]]

for obj in items {
  if let stringArray = obj as? [String] {
    print("\(stringArray)")
  }
}

또는 더 일반적으로 ( 이 다른 질문 답변 참조 ) :

for obj in items {
  if obj is [Any] {
    print("is [Any]")
  }

  if obj is [AnyObject] {
    print("is [AnyObject]")
  }

  if obj is NSArray {
    print("is NSArray")
  }
}

1

as?as데이터 유형 특정 유형인지 테스트하지 않고 데이터 유형을 특정 유형으로 변환 하거나 표현할 수있는 경우에만 테스트 하므로 예상 결과를 항상 제공 하지는 않습니다 .

예를 들어이 코드를 고려하십시오.

func handleError ( error: Error ) {
    if let nsError = error as? NSError {

Error프로토콜에 맞는 모든 데이터 유형을 NSError객체 로 변환 할 수 있으므로 항상 성공 합니다. 그러나 이것이 error실제로 NSError객체 또는 하위 클래스 라는 의미는 아닙니다 .

올바른 유형 검사는 다음과 같습니다.

func handleError ( error: Error ) {
    if type(of: error) == NSError.self {

그러나 정확한 유형 만 확인합니다. 의 서브 클래스도 포함 시키려면 다음 NSError을 사용해야합니다.

func handleError ( error: Error ) {
    if error is NSError.Type {

0

이와 같은 응답이있는 경우 :

{
  "registeration_method": "email",
  "is_stucked": true,
  "individual": {
    "id": 24099,
    "first_name": "ahmad",
    "last_name": "zozoz",
    "email": null,
    "mobile_number": null,
    "confirmed": false,
    "avatar": "http://abc-abc-xyz.amazonaws.com/images/placeholder-profile.png",
    "doctor_request_status": 0
  },
  "max_number_of_confirmation_trials": 4,
  "max_number_of_invalid_confirmation_trials": 12
}

is_stuckedAnyObject로 읽을 값을 확인하고 싶습니다.

if let isStucked = response["is_stucked"] as? Bool{
  if isStucked{
      print("is Stucked")
  }
  else{
      print("Not Stucked")
 }
}

0

서버의 응답으로 사전 또는 단일 사전의 배열을 얻을지 모른다면 결과에 배열이 포함되어 있는지 확인해야합니다.
제 경우에는 항상 한 번만 제외하고 여러 사전을받습니다. 그래서 그것을 처리하기 위해 신속한 3을 위해 아래 코드를 사용했습니다.

if let str = strDict["item"] as? Array<Any>

여기 요? 배열은 획득 한 값이 사전 항목의 배열인지 확인합니다. 그렇지 않으면 배열 안에 유지되지 않는 단일 사전 항목 인 경우 처리 할 수 ​​있습니다.


0

스위프트 5.2 & Xcode 버전 : 11.3.1 (11C504)

데이터 유형을 확인하는 솔루션은 다음과 같습니다.

 if let typeCheck = myResult as? [String : Any] {
        print("It's Dictionary.")
    } else { 
        print("It's not Dictionary.") 
    }

도움이 되길 바랍니다.


이전 질문에 대답 할 때 답변이 어떻게 도움이되는지를 설명하는 컨텍스트, 특히 이미 승인 된 질문이있는 질문에 대한 답변을 포함하면 다른 StackOverflow 사용자에게 훨씬 유용합니다. 좋은 답변을 작성하는 방법을 참조하십시오 .
David Buck
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.