2016-01-20 14 views
5

Im thử nghiệm Swift 2.0 và từ khóa mới defer trong một sân chơi:hoãn trong chức năng đã không làm việc trong Swift 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() 

tôi mong đợi bran"123yyy4xxx", nhưng nó thực sự là "123yyy4"

Tại sao defer (str += "xxx") của tôi không hoạt động như mong đợi?

+1

nó hoạt động nhưng 'defer' được gọi _after_ phạm vi chạy ra ngoài, do đó đầu tiên 'return str' được gọi là sau đó phạm vi chạy ra ngoài và nó gọi' defer' của bạn và thêm '" xxx "' vào cá thể cục bộ xảy ra _after_ giá trị trả về. – holex

Trả lời

7

Tuyên bố trì hoãn sẽ thực thi cho đến khi phạm vi hiện tại được thoát.

Đó là những gì táo nói. Vì vậy, câu lệnh trì hoãn sẽ được thực thi sau khi câu lệnh trả về. Đó là lý do tại sao bạn không thể nhìn thấy kết quả mong đợi.

5

Thứ nhất: defer được thực thi vì bạn có thể thấy rõ khi thêm print(str) vào đó.

Bây giờ để giải thích tại sao giá trị trả về không phản ánh giá trị thay đổi:
Lý do cho điều này là String là bất biến - bất cứ khi nào bạn viết str += something bạn tạo một String dụ hoàn toàn mới và lưu trữ nó bên trong str.

Nếu bạn viết return str trả về phiên bản hiện tại là str123yyy4. Sau đó, số defer được gọi và chỉ định String123yyy4xxx đến str hoàn toàn mới và không liên quan. Nhưng điều đó không thay đổi đối tượng String trước đó được lưu trữ bên trong str, nó chỉ ghi đè lên nó và do đó không ảnh hưởng đến return đã "xảy ra".

Nếu bạn thay đổi phương pháp của bạn để sử dụng NSMutableString thay vào đó bạn sẽ luôn luôn hoạt động trên cùng dụ và kết quả sẽ do đó một cách chính xác sản lượng 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() 

Trong mã rằng sự trở lại trả về Ví dụ lưu trữ trong str và trì hoãn thay đổi rằng dụ, nó không gán một cá thể mới nhưng thay đổi một cá thể đã có.

Đối với lời giải thích vì lợi ích bạn có thể thử để xem các địa chỉ bộ nhớ của str ở các giai đoạn khác nhau:

  • tại thời điểm return
  • trước khi thay đổi str trong khối defer
  • sau khi thay đổi nó

Đối với NSMutableString cả ba trường hợp sẽ mang lại cùng một địa chỉ bộ nhớ g rằng cá thể vẫn giữ nguyên. Tuy nhiên, String sẽ in hai địa chỉ bộ nhớ khác nhau dẫn đến Chuỗi được trả lại để trỏ đến someAddress và một số được hoãn lại để trỏ đến someOtherAddress.

+3

Lưu ý rằng 'unsafeAddressOf()' là hoàn toàn vô nghĩa với một chuỗi Swift (hoặc bất kỳ loại không phải lớp nào), nó trả về địa chỉ của một NSString tạm thời bắc cầu: http://stackoverflow.com/questions/32638879/swift-strings- và địa chỉ bộ nhớ. –

+0

@MartinR hmm:/bất kỳ ý tưởng gì tôi nên sử dụng thay vì để hình dung sự thay đổi bộ nhớ của thể hiện String? – luk2302

7

Greg là đúng và nếu bạn muốn để có được kết quả tương tự với mã của bạn thì bạn có thể làm theo cách này:

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

Các giải pháp dựa trên biến toàn cục hầu như không bao giờ là giải pháp tốt. Bạn cũng quên đặt lại biến 'str', vì vậy gọi' branch() 'nhiều lần cho các kết quả khác nhau. – Cristik

+0

Mã được cập nhật và cảm ơn đề xuất của bạn. –

Các vấn đề liên quan