2015-06-03 21 views
14

Zajmuję się tworzeniem aplikacji w Swift 2 (Xcode 7 beta 3) i próbuję użyć typów wartości (structs i enums) tam, gdzie to możliwe. Zgodnie z dokumentacją Apple dotyczącą zarządzania pamięcią, praca z typami wartości nie powinna powodować żadnych cykli zatrzymania i powinna po prostu działać.Przeciek pamięci w strukturach Swift - jak to naprawić?

Ale dziś spotkałem się z ogromną ilością wycieków pamięci w kodzie obsługi zdarzeń. Śledziłem to i zredukowałem problem do następującego minimalnego przykładu.

Można powiedzieć, że to protokół Item który definiuje pojedynczy obiekt value:

protocol Item { 

    var value: String { get } 

} 

Następnie tworzymy struct betonu, który implementuje protokół Item i dodaje dodatkową właściwość additionalValue. Nazwijmy strukturę FooItem.

struct FooItem<T>: Item { 

    let value: String 
    let additionalValue: T 

    init(value: String, additionalValue: T) { 
     self.value = value 
     self.additionalValue = additionalValue 
    } 

} 

Trzeci element układanki jest inna struktura, która owija element wykonawczy protokołu Item. Nazywa się ItemWrapper.

struct ItemWrapper { 

    let item: Item 

    init(item: Item) { 
     self.item = item 
    } 

} 

Jeżeli wyprofilowane instrumentami za pomocą pamięci Wycieki konfigurację przeciek pamięci pojawia się za każdym razem, gdy wartość ItemWrapper jest tworzony z FooItem.

let item = FooItem(value: "protocol value", additionalValue: "foo item value") 
let _ = ItemWrapper(item: item) 

Instruments screenshot 1 Instruments screenshot 2

Oto projekt Xcode przykład a Instruments złożyć: https://www.dropbox.com/s/z6ugxzxqggrv1xl/SwiftStructsMemoryLeak.zip?dl=0

The cały przykład kodu mogą być przeglądane w tym Gist: https://gist.github.com/lukaskubanek/4e3f7657864103d79e3a

Oto raport o błędzie: rdar: // 21375421

Czy to błąd w kompilatorze Swift, czy robię coś złego?


EDIT 1: Jak sugerowano w komentarzach, ja umieszczane na to pytanie na firmy Apple Dev Forum w celu zwrócenia większej uwagi ze Swift społeczności i potencjalnie z twórców języka. Ze względu na migrację forum dla programistów podczas WWDC 2015 musiałem opublikować zaktualizowane pytanie na nowych forach. Oto link: https://forums.developer.apple.com/message/9643


EDIT 2: Problem opublikowany pierwotnie w kodzie przykład wydaje się być rozwiązany w Swift 2.0. Ponieważ nie rozwiązało to problemów w mojej aplikacji, wprowadziłem kolejną modyfikację przykładowego kodu. Teraz dodatkowa właściwość FooItem ma typ ogólny, a FooItem jest opatrzony adnotacją typu, a zatem typem ogólnym. W ten sposób używam go w mojej aplikacji i nadal powoduje to przeciek pamięci, ale tym razem, gdy inicjuje się ItemWrapper, a nie podczas uzyskiwania dostępu do usługi.


EDIT 3: W pełni zaktualizowane pytanie zmodyfikowanego problemu, który utrzymuje się w Swift 2.0 i przekazany nowy projekt przykład Xcode.

+0

Co masz na myśli gdzie indziej - w kodzie lub dalszych środków na ten temat na innych stronach? –

+0

Przykładem są właśnie te 3 elementy i kod, który je wywołuje. Zobacz ten Gist https://gist.github.com/lukaskubanek/4e3f7657864103d79e3a dla całego AppDelegate. Przepraszam, że nie wspominam o tym w pytaniu. –

+0

Udało mi się odtworzyć problem, ale nie mam pojęcia, co się u diabła dzieje. +1 – Mazyod

Odpowiedz

4

Mimo że nie otrzymałem odpowiedzi od Apple ani na forach programistów, ani w narzędziu do śledzenia błędów i nie znalazłem nic dotyczącego tego problemu w uwagach do wydania najnowszych wersji beta, wydaje się, że został on rozwiązany w kompilatorze Swift w wersji Xcode 7 beta 5. (Może również działa w wersji beta 4. Ostatnia wersja, którą sprawdziłem, to wersja beta 3.)

Projekt demonstracyjny już nie powoduje przecieku pamięci. To samo dotyczy mojej aplikacji. Yay!

enter image description here

3

Cóż, oto sposób obejścia tego problemu, chociaż nie mam pojęcia, dlaczego to działa. Zauważyłem, że jeśli to zrobić:

let theItem = itemWrapper.item 
    let value = theItem.value 

... zamiast tego:

let value = itemWrapper.item.value 

... nie generuje wyciek pamięci.

+0

Znalazłem to obejście też. Problem polega na tym, że działa to tylko dla właściwości. W moim prawdziwym kodzie mam również metody zdefiniowane w protokole i generują również wycieki pamięci. Musiałem więc napisać funkcje owijające wszystkie konkretne typy (np. 'FooItem' itd.) I to nie jest zabawne. –

+0

Ale dzięki za miły połów! ;-) –

+0

Tak. Domyślam się, że jest to po prostu błąd w kompilatorze Swift, który (miejmy nadzieję) zostanie ostatecznie naprawiony, a "rozwiązaniem" jest po prostu wysłanie radaru i czekanie, aż Apple go zaadresuje. (Tam * jest * dyrektywa kompilatora, która pozwala włączyć "Swift Optimizations", która da ci inną kompilację, możesz spróbować włączyć to i zobaczyć, czy to naprawi.) Ale ostrzegaj, że również wprowadza pewne znane problemy, więc może być kompromisem.) –