Soru Swift de Downcasting isteğe bağlı: olarak? Yazın veya olarak! Tür?


Swift'de aşağıdakileri göz önünde bulundurun:

var optionalString: String?
let dict = NSDictionary()

Aşağıdaki iki ifade arasındaki pratik fark nedir?

optionalString = dict.objectForKey("SomeKey") as? String

vs

optionalString = dict.objectForKey("SomeKey") as! String?

76
2017-09-07 09:07


Menşei


Swift 2'deki tür dökümüne bakın fantageek.com/blog/2015/09/23/type-casting-in-swift - onmyway133
Aslo See Olarak! Apple'dan Operatör - Honey


Cevaplar:


Pratik fark şu:

var optionalString = dict["SomeKey"] as? String

optionalString tür bir değişken olacak String?. Altta yatan türden başka bir şey ise String bu zararsızca sadece atayacaktır nil isteğe bağlı.

var optionalString = dict["SomeKey"] as! String?

Bu diyor ki bilmek bu şey bir String?. Bu da sonuçlanacak optionalString tür olmak String?, fakat Altta yatan tür başka bir şey ise çökecektir.

İlk stil daha sonra if let isteğe bağlı olarak güvenle paketlemek için:

if let string = dict["SomeKey"] as? String {
    // If I get here, I know that "SomeKey" is a valid key in the dictionary, I correctly
    // identified the type as String, and the value is now unwrapped and ready to use.  In
    // this case "string" has the type "String".
    print(string)
}

121
2017-09-07 12:28



İlk yöntem her zaman daha iyi değil mi? Her ikisi de isteğe bağlı bir tür String döndürür? İkinci yöntem, ilk olanla aynı şeyi yapar gibi görünüyor, ancak downcast başarısız olursa çökebilir. Peki neden bunu kullanıyorsun? - Sikander
Evet @Sikander, ilki her zaman daha iyidir. Ben asla ikinciyi kullanmam. - vacawama


Vacawama'nın ne dediğini açıklığa kavuşturmak için, burada bir örnek ...

Hızlı 3.0:

import UIKit

let str_value:    Any   = String("abc")!
let strOpt_value: Any?  = String("abc")!
let strOpt_nil:   Any?  = (nil as String?)
let int_value:    Any   = Int(1)
let intOpt_value: Any?  = Int(1)
let intOpt_nil:   Any?  = (nil as Int?)

// as String
//str_value     as String // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//strOpt_value  as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//strOpt_nil    as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//int_value     as String // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//intOpt_value  as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//intOpt_nil    as String // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?

// as? String
  str_value     as? String // == "abc"
  strOpt_value  as? String // == "abc"
  strOpt_nil    as? String // == nil
  int_value     as? String // == nil
  intOpt_value  as? String // == nil
  intOpt_nil    as? String // == nil

// as! String
  str_value     as! String // == "abc"
  strOpt_value  as! String // == "abc"
//strOpt_nil    as! String // Run-Time Error: unexpectedly found nil while unwrapping an Optional value.
//int_value     as! String // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
//intOpt_value  as! String // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
//intOpt_nil    as! String // Run-Time Error: unexpectedly found nil while unwrapping an Optional value.

// as String?
//str_value     as String? // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//strOpt_value  as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//strOpt_nil    as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//int_value     as String? // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//intOpt_value  as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//intOpt_nil    as String? // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?

// as? String?
//str_value     as? String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
  strOpt_value  as? String? // == "abc"
  strOpt_nil    as? String? // == nil
//int_value     as? String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
  intOpt_value  as? String? // == nil
  intOpt_nil    as? String? // == nil

// as! String?
//str_value     as! String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
  strOpt_value  as! String? // == "abc"
  strOpt_nil    as! String? // == nil
//int_value     as! String? // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
//intOpt_value  as! String? // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
  intOpt_nil    as! String? // == nil

// let _ = ... as String
//if let _ = str_value    as String { true } // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_value as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_nil   as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = int_value    as String { true } // Compile-Time Error: 'Any' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_value as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_nil   as String { true } // Compile-Time Error: 'Any?' is not convertible to 'String'; did you mean to use 'as!' to force downcast?

// let _ = ... as? String
if let _ = str_value    as? String { true } // true
if let _ = strOpt_value as? String { true } // true
if let _ = strOpt_nil   as? String { true } // false
if let _ = int_value    as? String { true } // false
if let _ = intOpt_value as? String { true } // false
if let _ = intOpt_nil   as? String { true } // false

// let _ = ... as! String
//if let _ = str_value    as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = strOpt_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = strOpt_nil   as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = int_value    as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = intOpt_value as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'
//if let _ = intOpt_nil   as! String { true } // Compile-Time Error: initializer for conditional binding must have Optional type, not 'String'

// let _ = ... as String?
//if let _ = str_value    as String? { true } // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//if let _ = strOpt_value as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = strOpt_nil   as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = int_value    as String? { true } // Compile-Time Error: cannot convert value of type 'Any' to type 'String?' in coercion
//if let _ = intOpt_value as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?
//if let _ = intOpt_nil   as String? { true } // Compile-Time Error: 'Any?' is not convertible to 'String?'; did you mean to use 'as!' to force downcast?

// let _ = ... as? String?
//if let _ = str_value    as? String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
  if let _ = strOpt_value as? String? { true } // true
  if let _ = strOpt_nil   as? String? { true } // true
//if let _ = int_value    as? String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
  if let _ = intOpt_value as? String? { true } // false
  if let _ = intOpt_nil   as? String? { true } // true

// let _ = ... as! String?
//if let _ = str_value    as! String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
  if let _ = strOpt_value as! String? { true } // true
  if let _ = strOpt_nil   as! String? { true } // false
//if let _ = int_value    as! String? { true } // Compile-Time Error: cannot downcast from 'Any' to a more optional type 'String?'
//if let _ = intOpt_value as! String? { true } // Run-Time Error: Could not cast value of type 'Swift.Int' to 'Swift.String'.
  if let _ = intOpt_nil   as! String? { true } // false

Hızlı 2.0:

import UIKit

let str:    AnyObject   = String("abc")
let strOpt: AnyObject?  = String("abc")
let strNil: AnyObject?  = (nil as String?)
let int:    AnyObject   = Int(1)
let intOpt: AnyObject?  = Int(1)
let intNil: AnyObject?  = (nil as Int?)

str    as? String // == "abc"
strOpt as? String // == "abc"
strNil as? String // == nil
int    as? String // == nil
intOpt as? String // == nil
intNil as? String // == nil

str    as! String? // Compile-Time Error: Cannot downcast from 'AnyObject' to a more optional type 'String?'
strOpt as! String? // == "abc"
strNil as! String? // == nil
int    as! String? // Compile-Time Error: Cannot downcast from 'AnyObject' to a more optional type 'String?'
intOpt as! String? // Run-Time Error: Could not cast value of type '__NSCFNumber' to 'NSString'
intNil as! String? // == nil

10
2018-03-27 18:10



Örneğiniz için +1, ancak aynı örnekte olduğu gibi bana da açıklayabilir misiniz? olarak? Hücre = tableView.dequeueReusableCellWithIdentifier ("Hücre") olarak izinsiz olarak iken! UITableViewCell..i sanırım? neden yeterliydi? - Anish 웃
hücre = tableView.dequeueReusableCellWithIdentifier ("Hücre") olarak izin ver? UITableViewCell. - Burada UITableViewCell için "Hücre" tanımlayıcısı olan hücrenin aşağı döküm sonucunun bitip bitmediğini bilmiyoruz. Eğer nill olursa, o zaman nill verir (bu yüzden burada çarpışmayı önleriz). - jishnu bala
ilginç, intNil as! String? // ==nil Bir çarpışma neden olmaz !!! ???, İsteğe bağlı <Int> .Sadece isteğe bağlı <String> farklı değil. - onmyway133
neden serseri as? için String? Neden onu düşürmüyorsun String? ? Neden susturamıyorsun as! için String? - Honey
Bu oyun alanını Swift 3'te yapmaya teşebbüs, ama kullanmalısın Any yerine AnyObject - Honey


as? Types - aşağı döküm işleminin isteğe bağlı olduğu anlamına gelir. İşlem başarılı olabilir veya olmayabilir (aşağı döküm başarısız olursa sistem sıfırlanır). Aşağı döküm başarısız olursa herhangi bir şekilde çökmez.

as! Type? - İşte aşağı döküm süreci başarılı olmalı (! belirtir) . Son soru işareti, nihai sonucun sıfır olup olmayacağını belirtir.

"!" İle ilgili daha fazla bilgi ve "?"

2 vaka alalım

  1. Düşünmek:

    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell
    

    Burada UITableViewCell için "Hücre" tanımlayıcısı ile hücrenin aşağı döküm sonucunun başarılı olup olmadığını bilmiyoruz. Eğer başarısız olursa, o zaman nil döndürür (bu yüzden burada kilitlenmeyi önleriz). Aşağıda aşağıda belirtildiği gibi yapabiliriz.

    if let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as? UITableViewCell {
        // If we reached here it means the down casting was successful
    }
    else {
        // unsuccessful down casting
    }
    

    Öyleyse bunu böyle hatırlayalım - Eğer ? Bu, değerin sıfır olup olmadığından emin olmadığımız anlamına gelir (bir şey bilmediğimizde soru işareti gelir).

  2. Karşıtlık şunu:

    let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! UITableViewCell. 
    

    Burada derleyiciye aşağı dökümün başarılı olması gerektiğini söyledik. Başarısız olursa sistem çökecektir. Yani verdik ! Bu değerin sıfır olmadığından emin olduğumuzda.


10
2018-06-04 17:21





Onlar iki farklı biçim downcasting Swift'de.

(as?)olduğu bilinen Koşullu Form, downcast etmeye çalıştığınız türün isteğe bağlı bir değerini döndürür.

Downcast'in başarılı olup olmadığından emin olmadığınızda bunu kullanabilirsiniz.   Operatörün bu formu her zaman isteğe bağlı bir değer döndürecek ve   downcast mümkün değilse, değer sıfır olacaktır. Bu sağlar   başarılı bir downcast için kontrol etmek için.


(as!)olduğu bilinen Zorunlu Form, downcast'i dener ve sonucu tek bir bileşik eylem olarak kuvvetlendirir.

Kullanmalısın BİR TEK downcast olacağından eminseniz   her zaman başarılı olur. Operatörün bu formu bir Çalışma zamanı   hata Yanlış bir sınıf tipine indirmeye çalışırsanız.

Daha fazla bilgi için lütfen kontrol edin Türü Döküm Apple'ın belgelerinin bölümü.


7
2017-07-08 10:20





  • as köprülü tipte yayın ve döküm için kullanılır
  • as? Güvenli döküm için kullanılır, başarısız olursa iade edilir
  • as! döküm zorlamak için kullanılır, başarısız olursa çökme

Not:

  • as! isteğe bağlı olarak raw türünü kullanamaz

Örnekler:

let rawString: AnyObject = "I love swift"
let optionalString: AnyObject? = "we love swift"
let nilString: AnyObject? = (nil as String?)

let rawInt: AnyObject = Int(3)
let optionalInt: AnyObject? = Int(3)
let nilInt: AnyObject? = (nil as Int?)

Örnek

var age: Int? = nil
var height: Int? = 180

Ekleyerek bir ? Veri tipinden hemen sonra derleyiciye değişkenin bir sayı içerebileceğini veya olmadığını söylersiniz. Temiz! İsteğe bağlı sabitleri tanımlamanın gerçekten anlamlı olmadığına dikkat edin. Değerlerini yalnızca bir kez ayarlayabilirsiniz ve bu nedenle değerlerinin sıfır olup olmayacağını söyleyebilirsiniz.

Ne zaman kullanmalıyız? ve ne zaman "!"

UIKit tabanlı basit bir uygulama var diyelim. bizim kontrolörümde bazı kodlarımız var ve üstüne yeni bir görünüm denetleyicisi sunmak istiyoruz. ve navigasyon kontrol cihazını kullanarak yeni görünümü ekrana basmaya karar vermeliyiz.

Her ViewController örneğinin bir özellik navigasyon denetleyicisi olduğunu biliyoruz. Gezinme denetleyicisi tabanlı bir uygulama oluşturuyorsanız, uygulamanızın ana görünüm denetleyicisinin bu özelliği otomatik olarak ayarlanır ve denetleyicileri itmek veya görüntülemek için bunu kullanabilirsiniz. Tek bir uygulama projesi şablonu kullanırsanız - sizin için otomatik olarak oluşturulmuş bir gezinme denetleyicisi olmayacaktır. Bu nedenle, uygulamanızın varsayılan görüntüleme denetleyicisi, navigationController özelliğinde depolanan hiçbir öğeye sahip olmayacaktır.

Bunun bir Optional veri türü için tam olarak bir durum olduğunu zaten tahmin ettiniz. UIViewController'ı kontrol ederseniz, mülkün şöyle tanımlandığını görürsünüz:

var navigationController: UINavigationController? { get }

Şimdi kullanım durumumuza geri dönelim. Görünüm kontrolörünüzün her zaman bir navigasyon kontrol cihazına sahip olacağına dair bir gerçeği biliyorsanız, devam edip paketlemeyi zorlayabilirsiniz:

controller.navigationController!.pushViewController(myViewController, animated: true)

Sen koyduğun zaman! derleyiciye anlattığınız özellik adının arkasında Bu özelliğin isteğe bağlı olması umrumda değil, bu kod yürütüldüğünde her zaman bir değer deposu olacağını biliyorum, bu nedenle bu isteğe bağlı olarak normal veri türü gibi davranın. Peki bu hoş değil mi? Görünüm denetleyicinize navigasyon denetleyicisi olmasa ne olur? Eğer her zaman navigasyonda kayıtlı bir değer olacağını öneriyorsan, Controller yanlış mıydı? Uygulamanız çökecek. Bu kadar basit ve çirkin.

Öyleyse kullan! Sadece bu% 100 emin iseniz bu güvenlidir.

Her zaman bir navigasyon kontrolörü olacağından emin değil misiniz? O zaman kullanabilirsin? yerine !:

controller.navigationController?.pushViewController(myViewController, animated: true)

Ne? özellik adının arkasında derleyicinin olduğunu söyler Bu mülkün sıfır mı yoksa bir değer mi içerdiğini bilmiyorum, bu yüzden: eğer değeri varsa, ve oterwise tüm ifadeyi nil olarak düşünün. Etkili olarak? Bir navigasyon denetleyicisi olması durumunda bu özelliği kullanmanıza izin verir. Hayır, herhangi bir türden veya herhangi bir türden döküm varsa. Bu sözdizimi, bir navigasyon denetleyicinizin olup olmadığına dikkat etmediğinizde ve yalnızca bir şey yapmak istediğinizde mükemmel olduğunda mükemmeldir.

Büyük teşekkürler Fantageek


4
2018-03-31 20:20





Belki bu kod örneği, birisine prensipte yardımcı olur:

var dict = [Int:Any]()
dict[1] = 15

let x = dict[1] as? String
print(x) // nil because dict[1] is an Int

dict[2] = "Yo"

let z = dict[2] as! String?
print(z) // optional("Yo")
let zz = dict[1] as! String // crashes because a forced downcast fails


let m = dict[3] as! String?
print(m) // nil. the forced downcast succeeds, but dict[3] has no value

2
2017-07-03 18:54



Ayrıca, z2 = dict [2] olarak bırakın! Dize // "Yo" (isteğe bağlı değil) - Jay


İlki bir "koşullu yayın" (bağlandığım belgelerde "tür döküm operatörleri" nin altına bakın). Yayın başarılı olursa, ifadenin değeri isteğe bağlı olarak döndürülür ve döndürülür, aksi halde döndürülen değer geçersizdir.

İkincisi, optionalString'in bir string nesnesi olabileceği veya nil olabileceği anlamına gelir.

Bu soruda daha fazla bilgi bulundu.


0
2017-09-07 09:14