Niyə "örtülü açılmamış variantlar" yaradırsınız, buna görə də bu dəyərin nə olduğunu bilirsiniz?

Niyə müntəzəm dəyişən və ya daimi yaradan qarşı "Gizli açılmamış əlavə" yaratmaq lazımdır? Bunun uğurla yerləşdiriləcəyini bilirsinizsə, onda niyə opsiyonel bir seçim yaradın? Məsələn, niyə bu:

 let someString : String! = "this is the string" 

daha faydalı olacaq:

 let someString : String = "this is the string" 

"Seçenekler" sabit ya da değişkenin "heç bir dəyər" olmasına izin veriliyorsa, "lakin" bazen, bu dəyər ilk olaraq ayarlandıktan sonra seçenek her zaman önemlidir ki, proqram yapısından aydındır " İstədiyiniz parametr hər zaman əhəmiyyətli olduğunu bilirsinizsə ... İstəməz?

402
03 июня '14 в 7:09 2014-06-03 07:09 Johnston tərəfindən qeydə alınmış 03 iyun 'da 7:09 2014-06-03 07:09
@ 8 cavab

Yaradılan və konfiqurasiya edildikdə nil xüsusiyyətləri ola bilən bir obyektin vəziyyətini nəzərdən keçirin, lakin bundan sonra da dəyişməz və qeyri-sıfır (NSImage tez-tez bu şəkildə işlənir, baxmayaraq ki, hal-hazırda bəzən mutasiya etmək faydalıdır). Həssas olaraq yerləşdirilə bilən variantlar, nisbətən aşağı səviyyəli təhlükəsizlik itkisi ilə kodunuzu əhəmiyyətli dərəcədə təkmilləşdirə bilər (zəmanətlərdən biri qorunur, təhlükəsiz olacaq).

(Edit) Aydın olmaq üçün: müntəzəm seçimlər həmişə üstünlük təşkil edir.

104
03 июня '14 в 7:15 2014-06-03 07:15 Cavab Catfish_Man 03 iyun 'da verilir 7:15 2014-06-03 07:15

Həqiqi şəkildə açılmamış variantlar üçün istifadə hallarını təsvir edə bilməmişdən əvvəl, Swift-də hansı variantları və örtülü olaraq əlil variantları olduğunu anlamaq lazımdır. Əgər etməsəniz, mən ilk dəfə məqaləmə variantları haqqında oxumağı məsləhət görürəm .

Tamamilə əlil olan bir seçimi istifadə edərkən

Birbaşa örtülməmiş İstiqamət yarada biləcək dörd əsas səbəbi var. Bütün bunlar nil olduğunda heç vaxt mövcud olmayan bir dəyişənin tərifinə aiddir, çünki əks halda Swift kompilyatoru həmişə açıq bir şəkildə isteğe bağlı parametr yerləşdirməyi məcbur edəcək.

1. Başlanğıc zamanı müəyyən edilə bilməyən sabit.

Hər bir üzv sabitinin başlama vaxtından sonra dəyəri olmalıdır. Bəzən bir başlanğıc zamanı düzgün bir dəyəri ilə başlaya bilməz, ancaq girişdən əvvəl bir dəyərə sahib olacağına təmin edilə bilər.

İsteğe bağlı bir dəyişənin istifadəsi bu problemi atlayır, çünki isteğe bağlı parametr avtomatik olaraq nil ilə başlayır və nəticədə ehtiva edən dəyər hələ də eyni olacaq. Ancaq, sıfıra deyil, əmin olduğunuz bir dəyişənin daim yerləşdirilməsi üçün bir ağrı ola bilər. Tamamilə, Açılmayan Variantlar əlavə olaraq fayda verməklə, eyni şəkildə fayda verməyinizə əlavə olaraq üstünlük verirlər.

Bunun böyük bir forması şablonu yükləmədən əvvəl üzv dəyişənin UIView alt sinifində başlatılamamasıdır:

 class MyView : UIView { @IBOutlet var button : UIButton! var buttonOriginalWidth : CGFloat! override func awakeFromNib() { self.buttonOriginalWidth = self.button.frame.size.width } } 

Burada görünüşün yüklənməsinə qədər awakeFromNib orijinal genişliyini hesablaya bilmirsiniz, ancaq awakeFromNib görünüşdə (başlanğıc istisna olmaqla) hər hansı digər üsuldan əvvəl çağırılacağını bilirsiniz. Qiyməti sinif boyunca məqsədəuyğun şəkildə açılmağa məcbur etmək əvəzinə, bunu Gizli Açılmamış Əlavə olaraq elan edə bilərsiniz.

2. Objective-C API ilə qarşılıqlı əlaqə

Objective-C-də hər bir obyektin istinad göstəricisidir, yəni nil ola bilər. Bu, Swift-dan Objective-C API ilə hər bir qarşılıqlı bir obyekt istinad olduğu seçimi istifadə etməlidir. Bu halların hər birində Normal İstiqamətdən istifadə edə bilərsiniz, amma əmin olmağınızdan asılı olmayaraq linkin nil çıxmayacağı təqdirdə, açma kodunuzu Gizli açılmamış İsteğe bağlı olaraq elan edə bilərsiniz.

Bunun yaxşı bir nümunəsi UITableViewDataSource :

EDIT: UITableViewDataSource nümunəsi artıq etibarlı deyil. Apple API-yə aydınlıq gətirdi və parametrlərdən heç biri tələb olunmur və bir dönüş dəyəri deyil.

 override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell? { return nil } 

Burada metodu heç bir tableViewindexPath olmadan çağırılmayacağını tableView . nil üçün yoxlamaq üçün vaxt sərf olunacaq. Yalnız Swift API olsaydı, bunu isteğe bağlı olaraq elan etməzdi.

border=0

3. Ərizə nil yaradıcı dəyişəndən qurtara bilmədikdə.

Bu çox nadir olmalıdır, ancaq ərizəiniz işləməyə davam etmədikdə, dəyişkən olduqda nil olduqda nil üçün test üçün vaxt sərf olunacaq. Ərizənizin davam etməsi üçün tamamilə doğru olması lazım olan bir şərt varsa, adətən, assert . İsteğe Bağlı Açılmamış İsteğe Bağlı birbaşa daxil olan nil üçün bir bəyanat var.

4. NSObject Initializers

Apple ən azı bir qəribə vəziyyətə sahibdir. Texniki cəhətdən, NSObject dən miras qalan siniflərdən gələn bütün başlanğıclar Doğrudan Açılmamış Variantları qaytarır. Bu, Objective-C-də başlanğıcın nil dönə bilməsi ilə bağlıdır. Bu, bəzi hallarda, hələ də nil üçün başlama nəticəsini yoxlamaq istəyir. Bunun böyük bir nümunəsi, əgər şəkil mövcud deyilsə, UIImage :

 var image : UIImage? = UIImage(named: "NonExistentImage") if image != nil { println("image exists") } else { println("image does not exist") } 

Görünüşünüzün olmaması ehtimalı olduğunu düşünsəniz və bu scripti zərif bir şəkildə idarə edə bilərsinizsə, nil üçün yoxlaya bilərsiniz ki, başlanğıcın açıq şəkildə isteğe bağlı olaraq düzəldiyini bildirən bir dəyişən elan edə bilərsiniz. İsteğe Bağlı Açılmamış İsteğe Bağlı'yı burada da istifadə edə bilərsiniz, amma yenə də onu yoxlamaq üçün gedirsinizsə, adi İsteğe bağlı istifadə etmək daha yaxşıdır.

Əgər örtülü olaraq əlil olan seçimdən istifadə etmirsinizsə

Lazily Hesabı İstifadəçi Dəyişənlər

Bəzən sıfır olmamalı bir üzv dəyişən var, ancaq başlatma zamanı düzgün dəyərə ayarlana bilməz. Bir həlli Doğrudan Unwrapped istifadə etməkdir İsteğe bağlı, lakin ən yaxşı yolu bir tənbəl dəyişən istifadə etməkdir:

 class FileSystemItem { } class Directory : FileSystemItem { lazy var contents : [FileSystemItem] = { var loadedContents = [FileSystemItem]() // load contents and append to loadedContents return loadedContents }() } 

İndi üzv dəyişən contents ilk zəngdən əvvəl başlatılmaz. Bu, sinifə başlanğıc dəyərini hesablamadan əvvəl düzgün vəziyyəti daxil etmək imkanı verir.

Qeyd: Bu yuxarıda göstərilən # 1 sayğacına qarşı görünə bilər. Ancaq əhəmiyyətli bir fərq var. yuxarı buttonOriginalWidth zamanı müəyyən edilməli, belə ki, resursa çıxış etmədən əvvəl heç bir kəsin düymələri genişliyini dəyişdirməsin.

2. Else hər yerdə

Çox hissəsi üçün, əlil olaraq əlil olan variantlardan qaçınmalısınız, çünki yanlış istifadə edərsinizsə, tətbiqiniz çatdıqda və nil olduqda qəza edəcək. Değişkenin null olabileceğini heç vaxt bilmiyorsanız, her zaman normal olaraq istifadə edin. Heç vaxt nil olmayan dəyişənlərin yerləşdirilməsi əlbəttə çox zərər vermir.

397
05 июля '14 в 8:03 2014-07-05 08:03 cavab 05 iyul 'da saat 08:03 ' də verildi

Birbaşa genişlənmiş variantlar, xüsusilə örtüklər altında isteğe bağlı olmalıdırsa, bir mülkü isteğe bağlı olaraq təqdim etmək üçün faydalıdır. Tez-tez birbaşa istinad etmək üçün lazım olan iki əlaqəli obyekt arasında "bir nodu bağlamaq" zəruridir. Heç bir istinad ixtiyari olmadıqda mənfi olur, amma cüt biri sıfırlanmadan sıfır olmalıdır.

Məsələn:

 // These classes are buddies that never go anywhere without each other class B { var name : String weak var myBuddyA : A! init(name : String) { self.name = name } } class A { var name : String var myBuddyB : B init(name : String) { self.name = name myBuddyB = B(name:"\(name) buddy B") myBuddyB.myBuddyA = self } } var a = A(name:"Big A") println(a.myBuddyB.name) // prints "Big A buddy B" 

B hər hansı bir nüsxəsi həmişə etibarlı myBuddyA linkinə malik olmalıdır, buna görə də biz istifadəçini isteğe bağlı olaraq görmək istəmirik, ancaq linkə sahib myBuddyA B myBuddyA bilmək üçün biz myBuddyA ehtiyacımız var.

HƏMİ! Bu qarşılıqlı əlaqə tələbi tez-tez çətin bir link və yoxsul dizaynın göstəricisidir. Özünüzü dolaşan variantlara əsaslanaraq özünüzü taparsanız, ehtimal ki, cross-bağımlılıkları aradan qaldırmaq üçün refactoring haqqında düşünməlisiniz.

51
04 июня '14 в 1:44 2014-06-04 01:44 Cavab verilir n8gray 04 İyun '14 də 1:44 2014-06-04 01:44

Haşiyələnmiş variantlar mövcud Kakao çərçivələri və onların konvensiyalarını daha rahat etmək üçün lazım olan hibrid mühitdə işləmək üçün praqmatik bir kompromisdir və həmçinin sadə göstəricilər olmadan - Swift-dən daha təhlükəsiz bir proqramlaşdırma paradiqmasına addım-addım köç etməyə imkan verir.

"Swift" kitabı, "Əsaslar" bölməsində, "Əlavə olaraq əlil olan variantlar" bölməsi :

Seçkiqabağı genişlənmiş variantlar, isteğe bağlı olaraq əvvəlcədən seçildikdən dərhal sonra mövcud olan və bundan sonra hər bir nöqtədə mövcud ola biləcəyi ehtimal edildikdə təsdiq olunur. Sifariş başlanğıcında Swift-də qeyri - obyektiv tətbiq edilən variantların əsas istifadəsi, Unowned References-də və gizli açılmamış əlavə xüsusiyyətlərdə təsvir olunmuşdur.
...
Siz istifadə edildikdə avtomatik olaraq seçimi genişləndirmək üçün icazə verən gizli şəkildə yerləşdirilən bir seçim ilə çıxış edə bilərsiniz. Hər dəfə istifadə etdiyiniz seçimlərdən sonra hörmət işarəsi qoymaq əvəzinə, bəyan edərkən variantlar növü göstərildikdən sonra hörmət işarəsi qoyursunuz.

Bu qeyri- nil xüsusiyyətlərin istifadə razılaşması ilə təyin olunduğu və sinifin başlanğıcı zamanı kompilyator tərəfindən tətbiq oluna biləcək hallar istifadəyə verilir. Məsələn, UIViewController xüsusiyyətləri, NIB-dən və ya Storyboards-dan başlayır, burada başlatma fərdi mərhələlərə bölünür, lakin viewDidLoad() sonra xüsusiyyətləri adətən mövcud ola bilər. Əks halda, kompilyatoru təmin etmək üçün, kodun əsas məqsədini gizlətmək üçün yalnız məcburi genişləndirməni , isteğe bağlı bağlanmasını və ya isteğe bağlı bir zəncirdən istifadə etməlisiniz.

Kitabın yuxarı hissəsində Swift də avtomatik istinad sayma hissəsinə istinad edir :

Ancaq hər iki xüsusiyyət hər zaman bir dəyərə sahib olması üçün bir üçüncü ssenariyadır və heç bir mülkiyyət başlanmasından sonra heç nil olmamalıdır. Bu halda, bir sinifdə yararsız bir əmlakı başqa bir sinifdə gizli genişlənmiş əlavə xüsusiyyət ilə birləşdirmək faydalıdır.

Referans loopundan qaçınmaqla, bu, başlama tamamlandıqdan sonra birbaşa (əlavə yerləşdirmədən) birbaşa daxil olmaq üçün xassələri verir.

Çöp toplama dili deyilsiniz, buna görə də bir proqramçı kimi, gözləmə dövrünün pozulması və örtülü şəkildə istifadə edilən variantlar bu quirk gizlədir bir vasitədir.

"Kodunuzda tam olaraq genişlənmiş variantlardan istifadə edərkən?" bir sual. Bir proqram inkişaf etdiricisi olaraq, ənənəvi olaraq Objective-C-də yazılan kitabxana imza üsulları ilə tanış olursınız.

Cocoa və Objective-C ilə Swift-dən Zero ilə işləyən bölmə :

Objective-C hər hansı bir məhdudiyyətə zəmanət vermədiyindən, Swift obyekti, idxal olunan Objective-C API-lərində bütün növləri dəlillənmiş növlər və isteğe qaytarma növlərinə çevirir. Bir Objective-C obyektini istifadə etməzdən əvvəl, itkin olmadığından əmin olmalısınız.

Bəzi hallarda, bir Objective-C metodu və ya əmlak heç bir nil obyektinə müraciət etməyəcəyinə tam əmin ola bilərsiniz. Bu xüsusi script ilə işləmək üçün daha əlverişli obyektlər yaratmaq üçün, Swift idxal obyekti növlərini örtülü şəkildə genişləndirilmiş variantlar kimi. Əlavə tipli bütün təhlükəsizlik funksiyalarını əhatə edən geniş çeşidli variantlar daxildir. Bundan əlavə, birbaşa nil yoxlamadan və ya özünüzü maksimuma çatdırmadan dəyərə birbaşa daxil ola bilərsiniz. Əvvəlcə təhlükəsiz şəkildə yerləşdirilmədən bu növün bir növünə etibarlı bir şəkildə daxil olduqda, örtülü şəkildə genişləndirilmiş seçim dəyərin yoxluğunu yoxlayır. Bu dəyər itkisizsə, bir işləmə zamanı səhvi meydana gəlir. Nəticədə, dəyərin eksik olmağına əmin olmadıqda, həmişə yoxlanılmalı və seçilə bilən bir variantın özünüzü yerləşdirməlisiniz.

... və daha çox burada yalan söyləyirlər 2019

30
12 июня '14 в 17:06 2014-06-12 17:06 Cavab Palimondo tərəfindən 12 İyun '14 'də 17:06 2014-06-12 17:06 ' də verilir

Tək xəttli (və ya bir neçə xətt) sadə nümunələr variantların davranışını çox yaxşı təsvir edirlər - bəli, dəyişən elan edər və dərhal bir dəyərə işarə edirsinizsə, isteğe bağlı bir mənada heç bir məna yoxdur.

İndiyə qədər gördüyüm ən yaxşı vəziyyət, obyektin başlanmasından sonra baş verən ayardır, bundan sonra bu ayarı təqib etmək üçün "zəmanət" olduğunu izah edir. görünüşü nəzarətçi içində:

 class MyViewController: UIViewController { var screenSize: CGSize? override func viewDidLoad { super.viewDidLoad() screenSize = view.frame.size } @IBAction printSize(sender: UIButton) { println("Screen size: \(screenSize!)") } } 

printSize görünüşü yükləndikdən sonra çağırılacağını bilirik - bu görünüşün içərisindəki bir nəzarətə bağlı bir hərəkət metodudur və biz bunun əksini zəng etmədi. Buna görə də bəzi isteğe bağlı çekləri / bağlamaları saxlaya bilərik ! . Swift bu zəmanəni tanıyır (ən azı, Apple dayandırılması məsələsini həll etməyincə), belə ki, derivəyinizin mövcud olduğunu söylə.

Bəzi dərəcədə bu təhlükəsizlik səviyyəsini azaldır. Həqiqi şəkildə yerləşdirilən bir variant olduğunuz yerdə, "zəmanətiniz" həmişə yerinə yetirilmədikdə tətbiqinizin qəzalana biləcəyi yerdir, buna görə də bu xüsusiyyət az miqdarda istifadə olunur. Həm də istifadə edərkən ! Hər dəfə qışqırır kimi səslənir və heç kim onu ​​sevmir.

17
03 июня '14 в 7:26 2014-06-03 07:26 cavab iyun ayının 03-də saat 14: 30-da veriləcək

Apple Swift Proqramlaşdırma üçün böyük bir nümunə verir → Avtomatik Referans SayılarDərs nümunələri arasında güclü istinad dövrünə icazə verilməsiYayınlanmayan əlaqələr və örtülü şəkildə genişləndirilmiş inkişaf etmiş xüsusiyyətlər

 class Country { let name: String var capitalCity: City! // Apple finally correct this line until 2.0 Prerelease (let -> var) init(name: String, capitalName: String) { self.name = name self.capitalCity = City(name: capitalName, country: self) } } class City { let name: String unowned let country: Country init(name: String, country: Country) { self.name = name self.country = country } } 

City üçün başlanğıc ölkə üçün başlanğıcdan çağırılır. Buna baxmayaraq, Country üçün başlanğıc, İki mərhələli başlanğıcda təsvir edildiyi kimi, ölkənin yeni nüsxəsini tamamilə işə salınmadan City başlanğıcına self verə bilməz.

Bu tələbi yerinə yetirmək üçün capitalCity Country əmlakını gizli capitalCity bir mülk kimi elan capitalCity .

14
17 авг. Cavab verilir fujianjin6471 17 aug. 2015-08-17 12:47 '15 'də saat 12:47 ' da

Əgər qiymətin nil əvəzinə isteğe bağlı olaraq geri qaytarıldığını bilirsinizsə, Unwrapped Variantları Doğrudan bu dəyərləri seçimlərdən və birbaşa ələ keçirmək üçün isteğe bağlı seçimlərdən istifadə edə bilməz .

 //Optional string with a value let optionalString: String? = "This is an optional String" //Declaration of an Implicitly Unwrapped Optional String let implicitlyUnwrappedOptionalString: String! //Declaration of a non Optional String let nonOptionalString: String //Here you can catch the value of an optional implicitlyUnwrappedOptionalString = optionalString //Here you can't catch the value of an optional and this will cause an error nonOptionalString = optionalString 

Belə ki, istifadə arasında fərq var

let someString : String! və bir let someString : String

2
14 янв. cavab verildi enadun 14 yanvar. 2017-01-14 19:52 '17 saat 07:52 'də 2017-01-14 19:52

Gizli variantları əsaslandırmaq əvvəl yerləşdirmənin tətbiq olunması üçün əsaslandırıcıya baxaraq daha asan başa düşülür.

İstiqamətli (gizli və ya) istifadə etmək üçün zorla yerləşdirmə! operator, sizin kodunuzda səhv olmadığından əmin olmağınız və seçiminizin açıldığı bir dəyəri var. Olmadan! operator, ehtimal ki, yalnız isteğe bağlı bağlanma ilə iddia:

  if let value = optionalWhichTotallyHasAValue { println("\(value)") } else { assert(false) } 

bu qədər yaxşı deyil

 println("\(value!)") 

İndi gizli isteğe bağlı variantlar, mümkün olan bütün axınlardan açılmaqda həmişə dəyər verməyi düşündüyünüz seçimi müəyyən etməyə imkan verir. Beləliklə, o, sizə kömək etmək üçün bir addım atır - yazı tələblərini rahatlaşdırmaq! Hər dəfə yerləşdirmək və axınla bağlı fərziyyələr səhv olduğunda icra vaxtının hələ də səhv olduğundan əmin olun.

2
04 июня '14 в 1:59 2014-06-04 01:59 cavab Danra 04 iyun '14 saat 01:59 'də verilir 2014-06-04 01:59