Jeśli chcesz pełną kontrolę nad regionem pamięci przydzielić siebie, można użyć UnsafePointer
i Kolorado:
// allocate enough memory for ten Ints
var ump = UnsafeMutablePointer<Int>.alloc(10)
// memory is in an uninitialized raw state
// initialize that memory with Int objects
// (here, from a collection)
ump.initializeFrom(reverse(0..<10))
// memory property gives you access to the underlying value
ump.memory // 9
// UnsafeMutablePointer acts like an IndexType
ump.successor().memory // 8
// and it has a subscript, but it's not a CollectionType
ump[3] // = 6
// wrap it in an UnsafeMutableBufferPointer to treat it
// like a collection (or UnsafeBufferPointer if you don't
// need to be able to alter the values)
let col = UnsafeMutableBufferPointer(start: ump, count: 10)
col[3] = 99
println(",".join(map(col,toString)))
// prints 9,8,7,99,5,4,3,2,1,0
ump.destroy(10)
// now the allocated memory is back in a raw state
// you could re-allocate it...
ump.initializeFrom(0..<10)
ump.destroy(10)
// when you're done, deallocate the memory
ump.dealloc(10)
można również UnsafePointer
punkt do drugiej pamięci, takie jak pamięć jesteś wręczył niektóre API C.
UnsafePointer
można przekazywać do funkcji języka C, które pobierają wskaźnik do sąsiedniego bloku pamięci. Więc dla swoich celów, można następnie przekazać ten wskaźnik do funkcji jak mlock
:
let count = 10
let ump = UnsafeMutablePointer.allocate<Int>(count)
mlock(ump, UInt(sizeof(Int) * count))
// initialize, use, and destroy the memory
munlock(ump, UInt(sizeof(Int) * count))
ump.dealloc(count)
Można nawet posiadać własne typy niestandardowe:
struct MyStruct {
let a: Int
let b: Int
}
var pointerToStruct = UnsafeMutablePointer<MyStruct>.alloc(1)
pointerToStruct.initialize(MyStruct(a: 1, b: 2))
pointerToStruct.memory.b // 2
pointerToStruct.destroy()
pointerToStruct.dealloc(1)
Jednak mieć świadomość, jeśli robi to z klas lub nawet tablice lub łańcuchy (lub strukturę, która je zawiera), że wszystko, co będziesz trzymał w swojej pamięci, będzie wskazywać na inną pamięć, którą te obiekty przydzielają i posiadają. Jeśli ma to dla Ciebie znaczenie (np. Robisz coś specjalnego dla tej pamięci, na przykład zabezpieczając ją w twoim przykładzie), prawdopodobnie nie jest to, czego chcesz.
Musisz więc użyć obiektów o stałych rozmiarach lub użyć kolejnego UnsafePointer
do przechowywania wskaźników do większej liczby regionów pamięci. Jeśli nie trzeba dynamicznie zmieniać rozmiaru, to wystarczy jedna alokacja niebezpiecznego wskaźnika, ewentualnie opakowanego w interfejs użytkownika kolekcji UnsafeBufferPointer
.
Jeśli potrzebujesz bardziej dynamiczne zachowanie, poniżej jest realizacja bardzo goły z kolekcji, które można zmieniać rozmiaru w razie potrzeby, że można zwiększyć do pokrycia specjalne pamięci obsługę logicznych:
// Note this is a class not a struct, so it does NOT have value semantics,
// changing a copy changes all copies.
public class UnsafeCollection<T> {
private var _len: Int = 0
private var _buflen: Int = 0
private var _buf: UnsafeMutablePointer<T> = nil
public func removeAll(keepCapacity: Bool = false) {
_buf.destroy(_len)
_len = 0
if !keepCapacity {
_buf.dealloc(_buflen)
_buflen = 0
_buf = nil
}
}
public required init() { }
deinit { self.removeAll(keepCapacity: false) }
public var count: Int { return _len }
public var isEmpty: Bool { return _len == 0 }
}
na pokrycie wymagania MutableCollectionType
(tj CollectionType
powiększonej cesji indeksu):
extension UnsafeCollection: MutableCollectionType {
typealias Index = Int
public var startIndex: Int { return 0 }
public var endIndex: Int { return _len }
public subscript(idx: Int) -> T {
get {
precondition(idx < _len)
return _buf[idx]
}
set(newElement) {
precondition(idx < _len)
let ptr = _buf.advancedBy(idx)
ptr.destroy()
ptr.initialize(newElement)
}
}
typealias Generator = IndexingGenerator<UnsafeCollection>
public func generate() -> Generator {
return Generator(self)
}
}
I ExtensibleCollectionType
, aby umożliwić dynamiczny wzrost:
extension UnsafeCollection: ExtensibleCollectionType {
public func reserveCapacity(n: Index.Distance) {
if n > _buflen {
let newBuf = UnsafeMutablePointer<T>.alloc(n)
newBuf.moveInitializeBackwardFrom(_buf, count: _len)
_buf.dealloc(_buflen)
_buf = newBuf
_buflen = n
}
}
public func append(x: T) {
if _len == _buflen {
reserveCapacity(Int(Double(_len) * 1.6) + 1)
}
_buf.advancedBy(_len++).initialize(x)
}
public func extend<S: SequenceType where S.Generator.Element == T>
(newElements: S) {
var g = newElements.generate()
while let x: T = g.next() {
self.append(x)
}
}
}
Dlaczego po prostu nie stosujesz metody deinit tego obiektu, który posiada klucz i który usuwa klucz? – CouchDeveloper
@ 0x7fffffff - jakiego rodzaju dodatkowych informacji szukasz na podstawie mojej odpowiedzi? Będę musiał go dodać. –
@AirspeedVelocity Odpowiedź, którą podałeś, jest już wyjątkowa. Jeśli cokolwiek, po prostu szukam dodatkowego przykładu lub, jeśli to możliwe, wyjaśnienia, w jaki sposób można próbować ominąć problemy związane z łańcuchami i tablicami. (w większości tylko ciągi) Dzięki za kontynuację. –