オブジェクトがSwiftで指定されたタイプかどうかを確認する


267

で構成される配列がありAnyObjectます。繰り返し処理して、配列インスタンスであるすべての要素を見つけたいと思います。

Swiftでオブジェクトが特定のタイプかどうかを確認するにはどうすればよいですか?


あなたの質問は、特定のオブジェクトのタイプを見つけることについて尋ねていますが、オブジェクトが特定のタイプであるかどうかを確認することしかできない回答を受け入れました。質問を具体的に編集することをお勧めします。そうしないと、多くの読者があなたが受け入れた答えに不満を抱くでしょう。(他のすべての回答は類似しているので、幸いにも質問を絞り込んで無効にすることを心配する必要はありません。)
Jeremy Banks

この質問を編集して、スタックオーバーフロー.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]

一度に1つの要素を確認することもできます。

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 2014

あなただけ使用する必要があります@Unheilig asせずに?、あなたのプログラムは、オブジェクトは、それがない場合は、プログラムがすぐに停止しますので、そのタイプのものではないから回復できる方法がない場合。ステートメント?でin を使用すると、ifプログラムを続行できます。
drewag 2014

ご回答ありがとうございます。私が間違っている場合は私を修正してください:?この場合にを使用すると、「ジェネリック」タイプチェックが実行される場合は、if句に対して、そうでない場合はelse句に対して実行されると考えました。?elseがないと入力されず、指摘したようにランタイムエラーが発生します。再度、感謝します。
Unheilig 2014年

@Unheilig申し訳ありませんが、私はあなたが何を言っているのか、何を求めているのか理解できません。を使用?すると、代入が返されnil、ifステートメントが返さfalseれ、elseステートメントにフォールスルーします。ただし、説明は理解に役立つと思いますが、if let実際にはコンパイラの特別なケースです
drewag

1
@Unheilig正解です。ローカルスコープ内で値を変更したい場合は、varを使用できます(これらの変更はスコープ外には影響しません)
drewag

202

Swift 2.2-5では、次のことができます。

if object is String
{
}

次に、配列をフィルタリングします。

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

チェックするタイプが複数ある場合:

    switch object
    {
    case is String:
        ...

    case is OtherClass:
        ...

    default:
        ...
    }

このソリューションはより短いですが、デメリットがあります。(少なくともSwift 2では)を中括弧の内側objectとして使用することはできませんがStringletソリューションではそれを実行できます。
Ferran Maylinch 2017年

@FerranMaylinch objectブロックでの使用は問題ないので、意味を理解しないでください。
意味事項

-事項を意味する@あなたが行うことはできません例えばobject.uppercaseString、変数の型は、その型にキャストされていないので、あなただけの(変数が指す)オブジェクトであることを確認String
フェラン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.「The Swift Programming Language」iBooks

上記では、「特定のサブクラスタイプの」というフレーズが重要です。is Circleおよびの使用は、is Rectangleその値shapeShapeCircleおよびのスーパークラスRectangle)として宣言されているため、コンパイラーによって受け入れられます。

プリミティブ型を使用している場合、スーパークラスはになります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
プリミティブ型を配列に格納した場合、または配列がプリミティブ型の1つである場合isでも、ここで機能しますか?ありがとう。
Unheilig 2014年

objectas を宣言すると機能するはずですAny。例で更新されました。
GoZoner 2014年

返信ありがとうございます。それは有望に見えます。私の唯一の疑問は、以下の回答によれば、AnyObject提案されているように、AnyObjectから継承していないためにレトルト化されたように見えることNSObjectです。場合はAny異なっている、これは実際にだけでなく、偉大な解決策になります。ありがとう。
Unheilig 2014年

21

私には2つの方法があります。

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()関数は単純です:)
vivi

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) 

最後の4行はすべてtrueを返します。これは、

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

...もちろん "false"と表示されますが、CGRectからStringへのキャストが失敗するという警告が表示されます。したがって、いくつかのタイプはブリッジされ、「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 wayを使用し、定義された値を使用しなかったときにこれを提案しました。


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
}

Swift 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
それはスウィフトではありません。それはココアであり、それが目的C.のために働くだろうどこにのみ動作します
マット

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

サーバーからの応答で辞書の配列または単一の辞書を取得することがわからない場合は、結果に配列が含まれているかどうかを確認する必要があります。
私の場合、1回を除いて、常に辞書の配列を受け取ります。それで、私はそれを処理するために、迅速な3のために以下のコードを使いました。

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

ここに?Arrayは、取得した値が(辞書項目の)配列かどうかをチェックします。それ以外の場合は、配列内に保持されない単一のディクショナリ項目である場合に処理できます。


0

Swift 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ユーザーにとって非常に役立ちます。特に、既に回答が受け入れられている質問の場合はそうです。参照:良い答えを書くにはどうすればよいですか
デビッドバック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.