2015-01-19 6 views
3

Я пытаюсь переписать часть кода ObjC со Swift, многие свойства объекта какао возвращают необязательное значение в Swift. Есть ли лучше картина вместо этого глубокой вложенности:Unwrapping multiple Swift optionsals

if let panel = self.window { 
    if let screens = NSScreen.screens() { 
     if let screenRect = screens[0].frame { 
      let statusRect = CGRectZero 
       ... 
+0

возможно дубликат [Swift Необязательные связывание с кортежами] (http://stackoverflow.com/questions/27991378/swift-optional-binding-with-tuples) –

+0

смотри также HTTP: // StackOverflow .com/questions/24548999/unwrapping-multiple-optionsals-in-if-statement/25048307 # 25048307 –

+1

@AlexBrown Извините, я не думаю, что любой из этих вопросов точно совпадает с этим. Вопроситель говорит о цепочке опциональных. Взгляните на некоторые из приведенных ниже ответов.(Я не сомневаюсь, однако, что этот вопрос является обманом какого-то другого, а не того, с которым вы связались.) –

ответ

2

Хотя ответ Леонардо является хорошим, то это может привести к исключениям, если вы не знаете, объекты не являются необязательными, лучше картина этого, которую следует рассматривать как псевдокод:

if let frame = NSScreen.screens()?.first?.frame { 
    // Do something with frame. 
} 

других слова, использовать дополнительные цепочки (?.), но только с помощью let с самой последней частью цепи.

Вы также можете создать оператор, как это, если вы хотите цепи дополнительных опций, которые имеют другой типа, в котором только значение последнего будет возвращено:

infix operator ??? { associativity left } 

func ??? <T1, T2>(t1: T1?, t2: @autoclosure() -> T2?) -> T2? { 
    return t1 == nil ? nil : t2() 
} 

if let frame = self.window ??? NSScreen.screens()?.first?.frame { 
    // Do something with frame 
} 

Это, конечно, , вдохновленный связью Хаскелла. Но, как весело, я не рекомендую. Я думаю, это ясно, как грязь. (Кстати, разница между ??? и ?? является то, что бывший делает не требуют LHS и RHS быть одного и того же типа (или надтипа), в то время как последний делает. ??? всегда возвращает его RHS или nil.)

+0

@AlexBrown ссылка выше имеет хорошие точки и подробные объяснения, но этот ответ является самым элегантным. Единственным недостатком этого является то, что вы не знаете, какой из шагов был неудачным. –

+0

Если вам небезразлично, какие шаги не удались, не используйте этот подход. Вместо этого используйте комбинации '? .' и' if let'. –

+0

Спасибо, понял. –

1

Вы можете заставить разворачивать его так:

NSScreen.screens()!.first!.frame! 
NSScreen.screens()!.first!.frame!.width 
NSScreen.screens()!.first!.frame!.height 


// safely unwraping it as required an mentioned by Gregory 
if let frame = NSScreen.screens()?.first?.frame { 
    println(frame) 
} 
if let width = NSScreen.screens()?.first?.frame?.width { 
    println(width) 
} 
if let height = NSScreen.screens()?.first?.frame?.height { 
    println(height) 
} 
+1

Это небезопасно, приведет к сбою, если одно из значений равно нулю. –

+1

@SinisaDrpa Это правильно. –

1

I wrote a blog post a назад, который исследовал несколько различных способов развернуть несколько опций.

Вы можете создать функцию, которая разворачивает несколько УСТРОЙСТВА на одном дыхании:

func if_let<T, U, V>(a: Optional<T>, b: Optional<U>, 
    c: Optional<V>, fn: (T, U, V) ->()) { 
    if let a = a { 
    if let b = b { 
     if let c = c { 
     fn(a, b, c) 
     } 
    } 
    } 
} 

используется следующим образом:

if_let(a, b, c) { 
    a, b, c in 
    println("\(a) - \(b) - \(c)") 
} 

Кто-то предложил также изящное решение с помощью кортежей, которые могут быть found in this gist.

+0

Я нашел его раньше, отличный пост. Единственным недостатком является то, что вы сказали, что нет способа использовать разные цифры. параметров. нам нужны несколько версий одного и того же для 2,3 ... вложенных опций. –

+0

@SinisaDrpa очень верно, то же самое относится ко всем другим методам, которые я видел для достижения этого. Мы можем только ждать и надеяться на лучшую поддержку языка! – ColinE

0

Пожалуйста, прочитайте о необязательной сцепления здесь: Linking Multiple Levels of Chaining

И вы можете играть с этим игровая площадка, чтобы посмотреть, как она работает:

import UIKit 


class AAA { 
    var string: String? = nil 
} 

class AA { 
    var aaa: [AAA?]? = nil 
} 

class A { 
    var aa: AA? = nil 
} 


var a: A? 

a = A() 

/// Comment/Uncomment next lines 
a?.aa = AA() 
//a?.aa?.aaa = [AAA()] 
a?.aa?.aaa = [] 
a?.aa?.aaa?.first??.string = "My String Value" 

if let myString = a?.aa?.aaa?.first??.string { 
    print("myString: \(myString)") 
} else { 
    print("myString does not acceptable") 
} 

И ваш код может выглядеть так:

if let panel = self.window, let statusRect = NSScreen.screens()?.first??.frame ?? CGRect.zero { 
    /// your code to work with panel and statusRect 
} 
Смежные вопросы