Próbuję przekonwertować mostek Lua z Swift 2 na Swift 3. Nie jestem oryginalnym autorem, więc są pewne aspekty biblioteki, których nie znam zbyt dobrze, a oryginalny autor nie jest zainteresowany kontynuowaniem pracy nad projekt. Mam większość konwersji, ale pozostało jedno miejsce, w którym utknąłem i nie mogłem się zorientować. Próbowałem szukać w SO i Internecie, ale nie mogłem znaleźć niczego, co mogłoby mi pomóc rozwiązać problem.Jak przekonwertować "void *" powrót z funkcji C na "UnsafeMutableRawPointer" w Swift 3?
Jeśli ktoś jest zainteresowany patrząc na pełnym kodem źródłowym, tu jest mój widelec projektu na github: https://github.com/weyhan/lua4swift (mój zmianach w branży Swift3)
Pozwól mi Setup kontekst do błędu I” utknąłem na. Istnieje klasa Userdata, konkretnie w metodzie userdataPointer<T>() -> UnsafeMutablePointer<T>
funkcja c zwraca wartość bloku adresu danych użytkownika jako typ wskaźnika void *
.
oryginalny kod napisany w Swift 2:
public class Userdata: StoredValue {
public func userdataPointer<T>() -> UnsafeMutablePointer<T> {
push(vm)
let ptr = lua_touserdata(vm.vm, -1)
vm.pop()
return UnsafeMutablePointer<T>(ptr)
}
public func toCustomType<T: CustomTypeInstance>() -> T {
return userdataPointer().memory
}
public func toAny() -> Any {
return userdataPointer().memory
}
override public func kind() -> Kind { return .Userdata }
}
Po konwersji z Xcode 8 narzędzie do migracji, Xcode narzeka na przewodzie powrotnym z błędem Cannot invoke initializer for type 'UnsafeMutablePointer<T>' with an argument list of type '(UnsafeMutableRawPointer?)'
:
return UnsafeMutablePointer<T>(ptr)
Naprawiłem go z:
return (ptr?.assumingMemoryBound(to: T.self))!
Po powyższej zmianie, teraz Xcode 8 jest teraz skarżą się na oświadczenie wzywające w createCustomType
:
public func createCustomType<T: CustomTypeInstance>(setup: (CustomType<T>) -> Void) -> CustomType<T> {
lua_createtable(vm, 0, 0)
let lib = CustomType<T>(self)
pop()
setup(lib)
registry[T.luaTypeName()] = lib
lib.becomeMetatableFor(lib)
lib["__index"] = lib
lib["__name"] = T.luaTypeName()
let gc = lib.gc
lib["__gc"] = createFunction([CustomType<T>.arg]) { args in
let ud = args.userdata
// ******* Here's the line that is causing problem in Swift 3
(ud.userdataPointer() as UnsafeMutablePointer<Void>).destroy()
// *******
let o: T = ud.toCustomType()
gc?(o)
return .Nothing
}
if let eq = lib.eq {
lib["__eq"] = createFunction([CustomType<T>.arg, CustomType<T>.arg]) { args in
let a: T = args.customType()
let b: T = args.customType()
return .Value(eq(a, b))
}
}
return lib
}
Gdzie Utknąłem coraz to linia:
(ud.userdataPointer() as UnsafeMutablePointer<Void>).destroy()
wierzę oryginalny autor próbuje wyczyścić blok pamięci, gdzie wskaźnik zwracany przez wywołanie userdataPointer()
wskazuje.
pomocą narzędzia Xcode 8 automatycznej migracji powyższa linia przekształca się, jak poniżej:
(ud.userdataPointer() as UnsafeMutableRawPointer).deinitialize()
Jednakże Xcode się następnie zarzuca Cannot convert call result type 'UnsafeMutablePointer<_>' to expected type 'UnsafeMutableRawPointer'
.
Z moich badań wynika, że zmiana na linię powrotną w userdataPointer
wydaje się poprawna, więc myślę, że problem dotyczy obsady UnsafeMutableRawPointer. Próbowałem upuścić obsadę do UnsafeMutableRawPointer
i wywołać ud.userdataPointer().deinitialize()
bezpośrednio, ale pojawia się ten błąd Generic parameter 'T' could not be inferred
.
Inne rzeczy, których próbowałem, to przekonwertować UnsafeMutablePointer na UnsafeMutableRawPointer, ale zawsze powoduje to, że Xcode 8 narzeka na jedno lub drugie. Wszelkie sugestie, jak to zrobić?
Swift 3 migrator wydaje się konwersji tych '.memory' do '.pointee' w prawo. Masz rację, że wędrowiec wpadł w zamieszanie w kilku miejscach, ale generalnie działa w większości konwersji. Udało mi się to naprawić, zmieniając nieprawidłową linię na: 'UnsafeMutablePointer (ud.userdataPointer()). Deinitialize()' Myślę, że to jest poprawne, ale jeśli wiesz, że to źle, doceniłbym, gdybyś pozwolił ja wiem. Dzięki za długa analizę! –
To, co zrobiłeś, działa tak samo, jak sugerowałem. Tak czy inaczej, potrzebujemy rzutowania lub inicjalizacji tylko po to, aby powiedzieć kompilatorowi, co jest parametrem generycznym podczas wywoływania 'userdataPointer()'.Uważaj jednak: problematyczny wiersz w starym kodzie nie deinicjalizuje danych użytkownika. Nowy kod będzie. Jeśli kolejne wywołanie 'toCustomType()' spróbuje zwrócić ten sam obiekt userdata, zostanie ono już zdenokalizowane. Oczywiście nie znam kodu, po prostu dzielę się ogólnymi spostrzeżeniami. – OmniProg
Stary kod oznaczający tę linię? '(ud.userdataPointer() jako UnsafeMutablePointer) .destroy()'. Dzięki za heads up. Będę się nad tym zastanawiać. –