Swift'de Downcasting Seçenekleri: As? Yazın veya as! Tür?


96

Swift'de aşağıdakiler göz önüne alındığında:

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?

1
Aslo olarak görün ! Apple'dan Operatör
Honey

Yanıtlar:


144

Pratik fark şudur:

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

optionalStringbir tür değişkeni olacaktır String?. Temel tür a dışında bir Stringşeyse , bu zararsız bir nilşekilde isteğe bağlı olanı atayacaktır .

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

Bu benim diyor biliyorum bu şey bir olduğunu String?. Bu da bir optionalStringtür olmakla sonuçlanacaktır String?, ancak temeldeki tür başka bir şeyse çökecektir.

İlk stil daha sonra if letisteğe bağlı olanı güvenli bir şekilde açmak için kullanılır :

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)
}

İlk yöntem her zaman daha iyi değil mi? Her ikisi de isteğe bağlı bir String türü döndürür mü? Görünüşe göre ikinci yöntem ilki ile aynı şeyi yapıyor, ancak downcast başarısız olursa çökebilir. Öyleyse neden kullanıyorsun?
Sikander

6
Evet @Sikander, ilki her zaman daha iyidir. İkinciyi asla kullanmam.
vacawama

14

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

as! Type?- Burada aşağı çevrim işlemi başarılı olmalıdır (bunu !belirtir). Son soru işareti, nihai sonucun sıfır olup olmayacağını gösterir.

"!" Hakkında daha fazla bilgi ve "?"

2 vaka alalım

  1. Düşünmek:

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

    Burada, "Cell" tanımlayıcısına sahip hücrenin UITableViewCell'e aşağı çevrilmesinin sonucunun başarılı olup olmadığını bilmiyoruz. Başarısız olursa sıfır döndürür (bu nedenle burada çökmeyi önleriz). Burada aşağıda verildiğ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 şu şekilde hatırlayalım - Bu ?değerin sıfır olup olmadığından emin olmadığımız anlamına geliyorsa (soru işareti bir şeyleri bilmediğimizde gelir).

  2. Bunu şununla karşılaştırın:

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

    Burada derleyiciye aşağı çevrimin başarılı olması gerektiğini söylüyoruz. Başarısız olursa, sistem çökecektir. Yani !değerin sıfır olmadığından emin olduğumuzda veririz.


11

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

Swift 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

Swift 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

Örneğiniz için +1 ama bana aynı örnekle açıklayabilir misiniz? yerine? let hücre = tableView.dequeueReusableCellWithIdentifier ("Hücre") olarak aşağı yayın yaparken! UITableViewCell .. sanırım? neden yeterliydi!
Anish Parajuli 웃

let cell = tableView.dequeueReusableCellWithIdentifier ("Cell") as? UITableViewCell. - burada "Cell" tanımlayıcısına sahip hücrenin UITableViewCell'e aşağı dökümünün sonucunun sıfır olup olmadığını bilmiyoruz. Eğer sıfır ise sıfır olarak döner (bu yüzden burada çarpışmayı önleriz).
jishnu bala

ilginç, intNil as! String? // ==nilçökmeye neden olmaz !!! ???, İsteğe bağlı <Int>. Hiçbiri İsteğe Bağlı <String> 'den farklı değil. Hiçbiri
onmyway133

neden Downcast yapmak as?için String? Neden onu mahvetmiyorsun String?? Neden mahzun değil mi as!hiç String?
Honey

Bu oyun alanını Swift 3'te yapmaya çalışıyorum, ancak Anybunun yerine kullanmanız gerekiyorAnyObject
Honey

9
  • as yukarı döküm ve köprülü tipe tip döküm için kullanılır
  • as? güvenli yayın için kullanılır, başarısız olursa sıfır döndürür
  • as! döküm yapmaya zorlamak için kullanılır, başarısız olursa çökme

Not:

  • as! ham türü isteğe bağlı hale getiremez

Ö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?)

Misal

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

Bir ? Ekleyerek Veri türünün hemen ardından derleyiciye değişkenin bir sayı içerip içermeyeceğini söylersiniz. Düzgün! İsteğe bağlı sabitleri tanımlamanın gerçekten mantıklı olmadığına dikkat edin - değerlerini yalnızca bir kez belirleyebilir ve bu nedenle değerlerinin sıfır olup olmayacağını söyleyebilirsiniz.

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

Diyelim ki UIKit tabanlı basit bir uygulamaya sahibiz. görünüm denetleyicimizde bazı kodlar var ve bunun üzerine yeni bir görünüm denetleyicisi sunmak istiyoruz. ve gezinme denetleyicisini kullanarak ekrandaki yeni görünümü aktarmaya karar vermemiz gerekiyor.

Bildiğimiz gibi, her ViewController örneğinin bir özellik gezinti denetleyicisi vardır. 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 bunu, görünüm denetleyicilerini itmek veya açmak için kullanabilirsiniz. Tek bir uygulama projesi şablonu kullanıyorsanız - sizin için otomatik olarak oluşturulan bir gezinme denetleyicisi olmayacaktır, bu nedenle uygulamanızın varsayılan görünüm denetleyicisi, navigationController özelliğinde depolanan hiçbir şeye sahip olmayacaktır.

Eminim bunun bir İsteğe Bağlı veri türü için tam olarak bir durum olduğunu tahmin etmişsinizdir. UIViewController'ı işaretlerseniz, özelliğin şu şekilde tanımlandığını göreceksiniz:

var navigationController: UINavigationController? { get }

Öyleyse kullanım durumumuza geri dönelim. Görüntü denetleyicinizin her zaman bir gezinme denetleyicisine sahip olacağını biliyorsanız, devam edip onu açmaya zorlayabilirsiniz:

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

Ne zaman bir! özellik adının arkasında derleyiciye bu özelliğin isteğe bağlı olduğunu umursamadığımı söylüyorsunuz, bu kod çalıştırıldığında her zaman bir değer deposu olacağını biliyorum, bu nedenle bu İsteğe Bağlı normal bir veri türü gibi davranın. Güzel değil mi? Görünüm denetleyicinizde bir gezinme denetleyicisi yoksa ne olur? NavigationController'da her zaman bir değerin saklanacağını söylerseniz yanlış mıydı? Uygulamanız kilitlenecek. Bu kadar basit ve çirkin.

Öyleyse kullanın! sadece bunun güvenli olduğundan% 101 eminseniz.

Her zaman bir gezinme denetleyicisi olacağından emin değilseniz nasıl olur? O zaman kullanabilir misin? yerine !:

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

Nedir? özellik adının arkasında derleyiciye bu özelliğin nil mi yoksa bir değer mi içerdiğini bilmediğimi söyler , bu yüzden: eğer değeri varsa onu kullanın ve aksi takdirde tüm ifadeyi nil olarak düşünün. Etkili? bir gezinti denetleyicisi olması durumunda bu özelliği kullanmanıza izin verir. Herhangi bir türden kontrol veya herhangi bir tür döküm varsa hayır. Bu sözdizimi, bir gezinme denetleyicinizin olup olmadığı umrunda olmadığında ve yalnızca varsa bir şeyler yapmak istediğinizde mükemmeldir.

Fantageek'e çok teşekkürler


8

Swift'deki iki farklı Downcasting biçimidir .

as?Koşullu Form olarak bilinen ( ) , aşağıya doğru indirmeye çalıştığınız türün isteğe bağlı bir değerini döndürür.

Downcast'in başarılı olup olmayacağından emin olmadığınızda kullanabilirsiniz. Operatörün bu formu her zaman isteğe bağlı bir değer döndürür ve aşağı yayın mümkün değilse değer sıfır olur. Bu, başarılı bir çöküşü kontrol etmenizi sağlar.


as!Forced Form olduğu bilinen ( ) , indirimi dener ve sonucu tek bir bileşik eylem olarak zorla açar.

YALNIZCA mahzunluğun her zaman başarılı olacağından emin olduğunuzda kullanmalısınız . Operatörün bu formu, yanlış bir sınıf türüne indirgemeye çalışırsanız bir çalışma zamanı hatasını tetikler .

Daha fazla ayrıntı için lütfen Apple belgelerinin Tür Yayınlama bölümüne bakın.


4

Belki bu kod örneği birisinin ilkeyi altüst etmesine 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

Ayrıca, z2 = dikte [2] olsun! Dize // "Yo" (isteğe bağlı değil)
Jay



-1

Swift'e acemiyim ve bu örneği 'opsiyonelleri' anladığım kadarıyla açıklamaya çalışıyorum. Eğer yanılıyorsam lütfen beni düzeltin.

Teşekkürler.


class Optional {

    var lName:AnyObject! = "1"

    var lastName:String!
}

let obj = Optional()

print(obj.lName)

print(obj.lName!)

obj.lastName = obj.lName as? String

print(obj.lastName)

(1): obj.lastName = obj.lName as! String

vs

(2): obj.lastName = obj.lName as? String

Cevap: (1) Burada programcı “obj.lName”dizi tipi nesne içerdiğinden kesinlikle emindir . Öyleyse sadece bu değeri verin “obj.lastName”.

Şimdi, programcı doğruysa, "obj.lName"bunun anlamı dizge türü nesnedir, o zaman sorun yok. "obj.lastName" aynı değere ayarlanacaktır.

Ancak programcı yanlışsa "obj.lName", dizge türü nesne olmadığı anlamına gelir , yani "NSNumber" gibi başka tür nesneler içerir. Sonra CRASH (Çalışma Süresi Hatası).

(2) Programcı, “obj.lName”dizi türü nesne veya başka bir tür nesnesi içerdiğinden emin değildir . Öyleyse bu değeri “obj.lastName”dize türü ise olarak ayarlayın.

Şimdi, programcı doğruysa, “obj.lName”bunun anlamı dizge türü nesnedir, o zaman sorun yok. “obj.lastName”aynı değere ayarlanacaktır.

Ancak programcı yanlışsa, obj.lName dizge türü nesne olmadığı anlamına gelir, yani başka tür nesneler içerir "NSNumber". Sonra “obj.lastName”, sıfır değerine ayarlanır. So, No Crash (Happy :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.