UnsafePointer ja UnsafeMutablePointer
Lue ja kirjoita raakaa muistia huolellisesti.
UnsafePointer ja UnsafeMutablePointer on ilmainen Swift Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Swift Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Swift Academy-kurssilla on yhteensä 4 oppituntia.
Tyypitetyt osoittimet Swiftissä
Swiftin turvalliset viitteet eivät paljasta raakaosoitteita, mutta kun yhteensopivuutta tarvitaan C:n kanssa tai rakennetaan matalan tason tietorakenteita, käytetään tyypitettyjä osoittimia: UnsafePointer<T> vain lukuun ja UnsafeMutablePointer<T> lukuun ja kirjoittamiseen.
Tyypitetty osoitin tuntee elementin tyypin, joten se voi laskea siirtymät ja lukea oikein tyypitetyn arvon.
// A pointer to an Int we can read but not write
func readFirst(_ p: UnsafePointer<Int>) -> Int {
return p.pointee
}pointee-ominaisuus
pointee on arvo, johon osoitin tällä hetkellä viittaa. Muuttuvalla osoittimella voit sekä lukea että määrittää sen arvon; vain lukuun tarkoitetulla osoittimella voit ainoastaan lukea.
pointee-ominaisuuden käyttäminen alustamattomassa tai vapautetussa muistissa aiheuttaa määrittelemätöntä toimintaa — tyyppijärjestelmä ei havaitse tätä virhettä.
let p = UnsafeMutablePointer<Int>.allocate(capacity: 1)
p.initialize(to: 42)
print(p.pointee) // 42
p.pointee = 99
print(p.pointee) // 99Muistin varaaminen
UnsafeMutablePointer<T>.allocate(capacity:) varaa tilaa capacity määrälle elementtejä, mutta ei alusta niitä. Muisti on raakaa, ja sen lukeminen ennen alustusta on kiellettyä.
// Reserve space for 3 Doubles (uninitialized)
let buffer = UnsafeMutablePointer<Double>.allocate(capacity: 3)
// Must initialize before reading any elementAlustaminen ja alustuksen purkaminen
Ennen lukemista sinun on kutsuttava initialize-metodia. Ennen puhdistusta tarvitsevien tyyppien, kuten luokkien tai merkkijonojen, vapauttamista sinun on kutsuttava deinitialize-metodia niiden resurssien vapauttamiseksi.
Elinkaari on: allocate → initialize → use → deinitialize → deallocate.
let p = UnsafeMutablePointer<String>.allocate(capacity: 1)
p.initialize(to: "hello")
print(p.pointee)
p.deinitialize(count: 1) // releases the String
p.deallocate()Yhdistä allocate aina deallocateen
Jokaista allocate-kutsua kohden on tehtävä täsmälleen yksi deallocate-kutsu, muuten muisti vuotaa. defer-lauseen käyttäminen heti varauksen jälkeen on turvallisin toimintamalli, koska se suoritetaan riippumatta siitä, miten funktio päättyy.
func process() {
let p = UnsafeMutablePointer<Int>.allocate(capacity: 1)
defer { p.deallocate() }
p.initialize(to: 7)
print(p.pointee)
} // deallocate runs here automaticallyOsoitinlaskenta
Tyypitetyt osoittimet tukevat indeksointia ja laskentaa elementtiyksiköissä, eivät tavuissa. p + 2 siirtää osoitinta kahden T-tyypin siirtymän verran. p[i] on lyhenne ilmaisulle (p + i).pointee.
let p = UnsafeMutablePointer<Int>.allocate(capacity: 3)
p.initialize(repeating: 0, count: 3)
p[0] = 10
p[1] = 20
p[2] = 30
print((p + 1).pointee) // 20
p.deinitialize(count: 3)
p.deallocate()Useiden elementtien alustaminen
Muistilohkossa initialize(repeating:count:) asettaa jokaisen paikan samaan arvoon, kun taas initialize(from:count:) kopioi arvot toisesta puskurista. Molemmat alustavat koko alueen, joten sitä on turvallista lukea.
let dst = UnsafeMutablePointer<Int>.allocate(capacity: 4)
dst.initialize(repeating: 5, count: 4)
print(dst[3]) // 5
dst.deinitialize(count: 4)
dst.deallocate()Vain lukuun tarkoitettu ja muuttuva
Dataa vain tarkastelevan funktion tulee ottaa parametriksi UnsafePointer<T>; dataa muuttavan funktion tulee ottaa UnsafeMutablePointer<T>. Muuttuva osoitin muunnetaan implisiittisesti vain lukuun tarkoitetuksi osoittimeksi, mutta päinvastainen muunnos ei onnistu — näin rajapinta ilmaisee käyttötarkoituksen.
func sum(_ p: UnsafePointer<Int>, _ n: Int) -> Int {
var total = 0
for i in 0..<n { total += p[i] }
return total
}
// A mutable pointer can be passed here directlywithUnsafePointer paikallisille arvoille
Jos haluat olemassa olevaan arvoon kohdistuvan väliaikaisen osoittimen ilman varaamista, käytä withUnsafePointer(to:)-metodia tai sen muuttuvaa versiota. Osoitin on kelvollinen vain sulkeuman sisällä — älä koskaan päästä sitä sulkeuman ulkopuolelle.
var value = 100
withUnsafeMutablePointer(to: &value) { ptr in
ptr.pointee += 1
}
print(value) // 101Yleiset sudenkuopat
Tyypitetyt osoittimet ovat tehokkaita, mutta vaativat tarkkuutta:
pointee-ominaisuuden lukeminen enneninitialize-kutsua aiheuttaa määrittelemätöntä toimintaa.deinitialize-kutsun unohtaminen resursseja sisältäviltä tyypeiltä aiheuttaa vuotoja.withUnsafePointer-osoittimen päästäminen sulkeuman ulkopuolelle synnyttää roikkuvan osoittimen.
Kääntäjä luottaa tässä sinuun — ajonaikaisia suojakaiteita ei ole.
// DANGEROUS — pointer escapes the closure
// var escaped: UnsafePointer<Int>?
// withUnsafePointer(to: &x) { escaped = $0 }
// escaped!.pointee // dangling, undefined behaviorPieni käsin toteutettu pino
Kun yhdistät kaiken opitun: varaa lohko, käsittele sitä elementteinä indeksoinnin avulla ja siivoa lopuksi resurssit. Tämä on mukautettujen kokoelmien ja C-yhteensopivuuden perusta.
let n = 3
let stack = UnsafeMutablePointer<Int>.allocate(capacity: n)
stack.initialize(repeating: 0, count: n)
for i in 0..<n { stack[i] = i * i }
// stack now holds 0, 1, 4
stack.deinitialize(count: n)
stack.deallocate()Pikatarkistus
Palauta mieleen oikea osoittimen elinkaari.
Kertaus
Nyt tunnet tyypitetyt osoittimet:
UnsafePointerlukee,UnsafeMutablePointerlukee ja kirjoittaa.pointeekäsittelee arvoa; laskenta tapahtuu elementtiyksiköissä.- Elinkaari on allocate → initialize → use → deinitialize → deallocate, ja se kannattaa suojata
defer-lauseella.
Seuraavaksi näet, miten buffer-osoittimet käärivät kokonaisen yhtenäisen alueen Collection-ystävälliseksi rajapinnaksi.
Opi Swift tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 122
- Oppitunnit
- 409
Usein kysytyt kysymykset
Onko oppitunti ”UnsafePointer ja UnsafeMutablePointer” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Swift Academy-oppimispolun 3 oppituntia, myös oppitunnin “UnsafePointer ja UnsafeMutablePointer”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Swift Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”UnsafePointer ja UnsafeMutablePointer”?
Lue ja kirjoita raakaa muistia huolellisesti. Harjoittelet Swift Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Swift Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Swift Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.
Kuinka kauan ”UnsafePointer ja UnsafeMutablePointer”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Swift Academy-oppitunnilla?
Kyllä. Jokainen Swift Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- MemoryLayout ja kohdistus
- UnsafePointer ja UnsafeMutablePointer
- Unsafe-puskuriosoittimet
- withUnsafeBytes ja C-yhteentoimivuus