2016-01-20 25 views
5

イムテストスウィフト2.0やプレイグラウンドで新しいキーワードdefer動作しませんでした機能に延期:は、スウィフトに2.0

func branch() -> String { 

    var str = "" 

    defer { str += "xxx" } 
    str += "1" 

    let counter = 3; 

    if counter > 0 { 
     str += "2" 
     defer { str += "yyy" } 
     str += "3" 
    }  
    str += "4" 

    return str  
} 

let bran = branch() 

私は"123yyy4xxx"をするbranを期待するが、それは実際に"123yyy4"

のはなぜです私の延期は(str += "xxx")は期待どおりに動作しませんでしたか?

+1

それは動作しますが、スコープがなくなる_after_ 'defer'が呼び出され、したがって、最初に'return str'が呼び出されると、スコープがなくなり、' defer'が呼び出され、 '' xxx ''がローカルインスタンスに追加されます。 – holex

答えて

7

deferステートメントは、現在のスコープが終了するまで実行を延期します。

リンゴが言っていること。したがって、return文の後にdefer文が実行されます。だからあなたは期待された結果を見ることができません。

5

最初に:print(str)を追加すると明らかにわかるように、deferが実行されます。今

が返された値が変更された値を反映していない理由を説明する:
この理由は Stringは不変であるということです - あなたは str += somethingを書くたびに、まったく新しい Stringインスタンスを作成し、 str内に保管してください。

strの現在のインスタンス(123yyy4)を返すreturn strを書き込むとします。その後、deferが呼び出され、完全に新規で無関係のString123yyy4xxxstrに割り当てられます。しかし、以前のStringオブジェクトはstrの中に格納されていたものを変更することはなく、単純に上書きするため、すでに "発生した" returnには影響しません。

あなたの代わりにあなたが常に同じインスタンス上で動作しますNSMutableStringを使用するようにする方法を変更すると発生しますので、正しく出力さ123yyy4xxx場合:

そのコードで
func branch() -> NSMutableString { 
    var str = NSMutableString() 
    defer { str.appendString("xxx") } 
    str.appendString("1") 
    let counter = 3; 
    if counter > 0 { 
     str.appendString("2") 
     defer { str.appendString("yyy") } 
     str.appendString("3") 
    } 
    str.appendString("4") 
    return str 
} 


let bran1 = branch() 

リターンはstrに保存されたインスタンスを返します遅延はのインスタンスに変更されますが、新しいインスタンスは割り当てられませんが、すでに存在するインスタンスは変更されます。あなたはさまざまな段階でstrのメモリアドレスを表示しようとすることができます説明の便宜上

  • return
  • の時に、それを変更した後deferブロック
  • strを変更する前

NSMutableStringの場合、3つすべてのケースで同じメモリアドレスが返されますg インスタンスは同じままです。しかし、Stringは2つの異なるメモリアドレスを出力し、返されるStringはsomeAddressを指し、遅延されたものはsomeOtherAddressを指す。

+3

'unsafeAddressOf()'はSwift文字列(または非クラス型)では完全に無意味ですが、一時的にブリッジされたNSStringのアドレスを返します:http://stackoverflow.com/questions/32638879/swift-strings-およびメモリアドレスを含む。 –

+0

@MartinR hmm:/任意のアイデア代わりにStringインスタンスのメモリ変更を視覚化するために使用する必要がありますか? – luk2302

7

グレッグが正しく、あなたのコードと同じ結果を取得したい場合、あなたはこのようにそれを行うことができます。

var str = "" 

func branch() { 

    str = "" 
    defer { str += "xxx" } 
    str += "1" 


    let counter = 3 

    if counter > 0 { 
     str += "2" 
     defer { str += "yyy" } 
     str += "3" 
    } 
    str += "4" 

} 

branch() 
str //"123yyy4xxx" 
+2

グローバル変数ベースのソリューションは、決して良いソリューションではありません。また、 'str'変数をリセットするのを忘れたので、' branch() 'を複数回呼び出すと、異なる結果が得られます。 – Cristik

+0

コードが更新され、あなたの提案に感謝します。 –