---
title: 'Arka Plan Aktarımı'
source: 'https://academia.sh/tr/kurslar/ios-veri-ve-ag/arka-plan-aktarimi'
course: 'Veri, Ağ ve Eşzamanlılık'
language: tr
updated: '2026-10-21T05:03:09+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Arka plan oturumunun aktarımı uygulamadan ayrı bir süreçte sürdürdüğünü açıklar'
    - 'Yeniden açılışta sistemin sürdürdüğü aktarımları denetlemeden kuyruğa almanın dosyayı çoğalttığını ölçer'
    - 'Görev tanımlayıcısına göre kayıt tutmanın aynı durumda sağlam kaldığını gösterir'
    - 'Sistemin aktarımı ne zaman sürdüreceğinin modelin dışında kaldığını söyler'
---

# Arka Plan Aktarımı

Uygulama arka plandayken sistemin sürdürdüğü indirmeler; yeniden açılışta listeyi denetlemeden yeniden kuyruğa almanın aynı dosyayı iki kez indirmesinin ölçümü.

Kullanıcı büyük bir dosya indirmeye başlayıp uygulamadan çıkabilir. Normal bir oturumda uygulama arka plana geçince aktarım kesilir. **Arka plan aktarımı** (background transfer) bunu değiştirir: aktarımı sistem yürütür ve uygulama sistem tarafından sonlandırılsa bile sürdürür. Bitince ya da gerektiğinde uygulamayı uyandırır.

Bu düzenin bir sonucu var: uygulama yeniden açıldığında bazı aktarımlar zaten sürüyordur. Uygulamanın kendi listesi bu durumu bilmez. Listeyi olduğu gibi yeniden kuyruğa almak, sistemin zaten yürüttüğü bir aktarımı ikinci kez başlatmak olabilir. Çekirdek aynıdır.

```swift
// Replay.swift — bir islemin yinelemeye ve siraya duyarliligini siniflandirir
struct Trial<State: Equatable & CustomStringConvertible> {
    let label: String
    let once: State
    let twice: State
    let forward: State
    let backward: State

    var sensitivity: String {
        switch (once != twice, forward != backward) {
        case (false, false): return "saglam"
        case (true, false): return "yinelemeye-duyarli"
        case (false, true): return "siraya-duyarli"
        case (true, true): return "cift-duyarli"
        }
    }

    func report() -> String {
        print("\(label) | bir=\(once) iki=\(twice) ab=\(forward) ba=\(backward) -> \(sensitivity)")
        return sensitivity
    }
}

func replay<State>(_ label: String, from start: State, _ a: (State) -> State, then b: (State) -> State) -> Trial<State> {
    Trial(label: label, once: a(start), twice: a(a(start)), forward: b(a(start)), backward: a(b(start)))
}

func countSensitivities(_ results: [String]) {
    for name in ["saglam", "yinelemeye-duyarli", "siraya-duyarli", "cift-duyarli"] {
        print("\(name): \(results.filter { $0 == name }.count)")
    }
}
```

## Aktarım Kaydı

Model, uygulamanın bildiği aktarım kaydını kurar. Her aktarım bir tanımlayıcıyla anılır ve kayıt sıralı tutulur. İki kuyruğa alma biçimi karşılaştırılır: tanımlayıcıya bakmadan ekleyen ve önce bakan.

```swift
// Transfers.swift — aktarim kaydi ve iki kuyruga alma bicimi
struct Registry: Equatable, CustomStringConvertible {
    var tasks: [String] = []
    var description: String { "[" + tasks.joined(separator: ",") + "]" }
}

func enqueueAll(_ files: [String]) -> (Registry) -> Registry {
    { registry in Registry(tasks: (registry.tasks + files).sorted()) }
}

func enqueueIfMissing(_ files: [String]) -> (Registry) -> Registry {
    { registry in
        let missing = files.filter { !registry.tasks.contains($0) }
        return Registry(tasks: (registry.tasks + missing).sorted())
    }
}

func finish(_ file: String) -> (Registry) -> Registry {
    { registry in Registry(tasks: registry.tasks.filter { $0 != file }) }
}
```

`enqueueAll` listedeki her dosya için yeni bir aktarım ekler. `enqueueIfMissing` yalnız kayıtta olmayanları ekler. `finish` bir aktarımın tamamlandığını kurar. **Model yalnız uygulamanın kayıt defterini kurar; sistemin aktarım yürütmesi ya da diskin kendisi değildir.** Ölçümde başlangıç durumu, uygulama kapanmışken sistemin `a.zip` indirmesini sürdürdüğü bir yeniden açılıştır.

```swift
// main.swift — yeniden acilista iki kuyruga alma bicimi
let reopened = Registry(tasks: ["a.zip"])
let wanted = ["a.zip"]

let blind = replay("denetlemeden-kuyruga-al", from: reopened, enqueueAll(wanted), then: enqueueAll(wanted)).report()
let byIdentifier = replay("tanimlayiciya-gore", from: reopened, enqueueIfMissing(wanted), then: enqueueIfMissing(wanted)).report()

countSensitivities([blind, byIdentifier])
```

```
denetlemeden-kuyruga-al | bir=[a.zip,a.zip] iki=[a.zip,a.zip,a.zip] ab=[a.zip,a.zip,a.zip] ba=[a.zip,a.zip,a.zip] -> yinelemeye-duyarli
tanimlayiciya-gore | bir=[a.zip] iki=[a.zip] ab=[a.zip] ba=[a.zip] -> saglam
saglam: 1
yinelemeye-duyarli: 1
siraya-duyarli: 0
cift-duyarli: 0
```

`denetlemeden-kuyruga-al` yinelemeye duyarlıdır. Sistem `a.zip`'i zaten yürütüyordu; liste yeniden kuyruğa alınınca ikinci bir `a.zip` kaydı oluştu ve bir daha alınınca üçüncüsü. Aynı dosya art arda iki kez indirilir. `tanimlayiciya-gore` sağlamdır: tanımlayıcı kayıtta olduğu için kuyruğa alma hiçbir şey eklemez, kaç kez yapılırsa yapılsın.

**AG16.** Model sistemin sürdürdüğü aktarımı uygulamanın kaydında bulunur sayar. Gerçekte uygulama kaydı kendisi sistemden sorgulayarak kurar.

**AG17.** Model aynı dosyanın iki kaydını iki ayrı indirme sayar. İki kayıt gerçek bir uygulamada aynı hedef dosyaya yazılırsa biri ötekinin üstüne yazabilir.

## Arka Plan Oturumu

Arka plan aktarımı, tanımlayıcılı özel bir yapılandırmayla kurulur.

```swift
import Foundation

let configuration = URLSessionConfiguration.background(withIdentifier: "downloads")
configuration.sessionSendsLaunchEvents = true
let session = URLSession(configuration: configuration, delegate: downloader, delegateQueue: nil)

let task = session.downloadTask(with: URL(string: "https://files.example.com/a.zip")!)
task.taskDescription = "a.zip"
task.resume()
```

Bu parça KAYNAK kalır. Yapılandırmanın tanımlayıcısı, uygulama yeniden açıldığında aynı oturuma yeniden bağlanmayı sağlar. Yeniden bağlanan oturum, sürmekte olan görevleri sorgulayabilir.

```swift
import Foundation

func pendingFiles(of session: URLSession) async -> Set<String> {
    let tasks = await session.allTasks
    return Set(tasks.compactMap(\.taskDescription))
}
```

Bu da KAYNAK kalır. Model bu sorgunun sonucunu `Registry` olarak temsil eder; `enqueueIfMissing` bu kümeyle kuyruğa almadan önce karşılaştırır. Aktarım bitince sonucu bir **temsilci** alır ve dosya geçici konumdan kalıcı bir yere taşınmalıdır.

```swift
import UIKit

final class AppDelegate: UIResponder, UIApplicationDelegate {
    var completionHandlers: [String: () -> Void] = [:]

    func application(_ application: UIApplication,
                     handleEventsForBackgroundURLSession identifier: String,
                     completionHandler: @escaping () -> Void) {
        completionHandlers[identifier] = completionHandler
    }
}
```

Sistem uygulamayı arka planda uyandırırsa bu **uygulama temsilcisi** işleyicisini çağırır. Uygulama, olaylar bitince saklanan **kapanışı** çağırarak sisteme işini bitirdiğini bildirir.

## Aktarımı Sistemin Yürütmesi

Arka plan oturumunun temel fikri, aktarımın uygulamanın ömrüne bağlı olmamasıdır. Sıradan bir oturumda bir indirme, uygulama arka plana geçtikten kısa süre sonra kesilir; çünkü sistem uygulamayı askıya alır. Arka plan oturumunda ise indirmeyi uygulamadan ayrı bir sistem süreci yürütür. Uygulama askıya alınsa, hatta kullanıcı tarafından sonlandırılmasa bile sistem tarafından kapatılsa, aktarım sürebilir. İş bitince sistem uygulamayı gerektiğinde uyandırır ve sonucu teslim eder.

Bu düzenin bedeli, uygulamanın artık aktarımın tek sahibi olmamasıdır. Aktarımın durumunu sistem tutar; uygulamanın elindeki liste yalnız bir kopyadır. Uygulama kapalıyken aktarım tamamlanmış, başarısız olmuş ya da hâlâ sürüyor olabilir ve uygulama yeniden açıldığında bu üç durumu sistemden sormadan bilemez. Modeldeki `Registry` uygulamanın bu kopyasını kurar; `denetlemeden-kuyruga-al` satırı, kopyanın gerçeğe uymadığı bir yeniden açılışta ne olduğunu gösterir.

## Gerçek Uygulamada Nerede Görülür

Bir podcast uygulamasında kullanıcı on bölüm indirmek üzere kuyruğa alır ve telefonu cebine koyar. Uygulama arka plana geçer, sistem indirmeleri sürdürür. Kullanıcı bir saat sonra uygulamayı açtığında bölümlerin bir kısmı inmiş, bir kısmı sürüyordur. Uygulamanın açılışta yaptığı ilk iş, "indirilecekler" listesini yeniden kuyruğa almaksa, sürmekte olan bölümler ikinci kez başlatılır. Aynı dosya iki kez indirilir; veri tarifesi harcanır, pil tükenir ve iki aktarım aynı hedef dosyaya yazmaya çalışırsa dosya bozulabilir.

Bir ikinci durum kullanıcının uygulamayı kendisinin kapatmasıdır. Kullanıcı uygulamayı çoklu görev ekranından sonlandırırsa sistem oturumun arka plan aktarımlarını iptal eder ve uygulamayı kullanıcı yeniden açana kadar kendiliğinden başlatmaz. Bu davranış sistemde gerçekleştiği için burada ölçülmez; uygulama yeniden açıldığında hangi aktarımların hâlâ sürdüğünü sormak, bu iki durumu ayırmanın tek güvenli yoludur.

## Yanlış Kurulum ve Düzeltmesi

Yanlış kurulum, açılışta kayıtlı listeyi doğrudan yeniden kuyruğa almaktır.

```swift
import Foundation

// Yanlış: açılışta liste olduğu gibi yeniden kuyruğa alınır
func resumeDownloads(_ files: [URL], using session: URLSession) {
    for file in files {
        let task = session.downloadTask(with: file)
        task.taskDescription = file.lastPathComponent
        task.resume()
    }
}
```

Bu parça KAYNAK kalır. Düzeltme, önce sistemden sürmekte olan görevleri sormak ve yalnız eksik olanları kuyruğa almaktır.

```swift
import Foundation

// Düzeltme: sürenleri sor, eksik olanları kuyruğa al
func resumeDownloads(_ files: [URL], using session: URLSession) async {
    let running = Set(await session.allTasks.compactMap(\.taskDescription))
    for file in files where !running.contains(file.lastPathComponent) {
        let task = session.downloadTask(with: file)
        task.taskDescription = file.lastPathComponent
        task.resume()
    }
}
```

Bu da KAYNAK kalır. `taskDescription` burada görev tanımlayıcısı olarak kullanılır: kuyruğa alınırken yazılır ve açılışta okunur. Ölçümdeki `tanimlayiciya-gore` satırı bunun modelidir: tanımlayıcı kayıtta varsa kuyruğa alma bir şey eklemez ve işlem kaç kez tekrarlanırsa tekrarlansın kayıt aynı kalır. Düzeltilmiş işlevin sağlamlığı yinelemeye karşıdır; sıraya karşı değildir. Bir aktarım biterken aynı anda kuyruğa alınırsa sonuç, ölçümde gördüğümüz gibi, işlemlerin sırasına bağlıdır.

## Oturumun Yaşam Döngüsü

Arka plan oturumu tanımlayıcısıyla anılır ve bu tanımlayıcı oturumun kimliğidir. Uygulama aynı tanımlayıcıyla yeni bir oturum kurduğunda sistem, o tanımlayıcıya ait sürmekte olan görevleri yeni oturuma bağlar. Tanımlayıcı her açılışta farklı üretilirse bu bağ kurulamaz; eski görevler sahipsiz kalır ve uygulama yeni bir görev kümesiyle başlar. Ölçümdeki `tanimlayiciya-gore` satırı bu yüzden bir koşula bağlıdır: kayıt defterinin sistemin gerçek durumuyla uyumlu olması ve tanımlayıcının kalıcı olması.

Yaşam döngüsü şöyle işler. Uygulama görevi kuyruğa alır ve arka plana geçer. Sistem görevi yürütür. Görev biterse ya da kimlik doğrulama gibi bir olay gerekirse sistem uygulamayı arka planda başlatır ve oturumun temsilcisine olayları iletir. Temsilci olayları işledikten sonra, sistemin verdiği kapanışı çağırır. Bundan sonra sistem uygulamayı yeniden askıya alabilir. Kullanıcı uygulamayı kendisi açtığında ise aynı tanımlayıcıyla oturum kurulur ve bekleyen olaylar teslim edilir.

## Yeniden Açılışta Denetim

Yeniden açılışın ilk işi, sistemin ne yaptığını sormaktır. Sürmekte olan görevlerin listesi alınır, tamamlanmış ancak henüz işlenmemiş sonuçlar temsilciye teslim edilir ve kayıt defteri bu bilgilerle güncellenir. Ancak bundan sonra eksik kalan dosyalar için yeni görevler kuyruğa alınır. Bu sıra `denetlemeden-kuyruga-al` ile `tanimlayiciya-gore` arasındaki farkın pratikteki karşılığıdır: birincisi listeyi kendisi doğru sanır, ikincisi sistemin gerçeğini sorar.

Denetim bir kez yapıldığında yeterli değildir. Uygulama açık kalırken de görevler tamamlanır, başarısız olur ya da iptal edilir. Kayıt defteri bu olaylarla güncel tutulmazsa bir sonraki açılışta eski bilgiyle denetim yapılır. `finish` işleminin modele konma nedeni budur: bitmiş bir aktarımın kayıttan çıkması gerekir, yoksa kayıt gerçekte olmayan bir aktarımı var sayar. Sınırlayıcı ölçümde gördüğümüz sıra duyarlılığı bu güncellemenin zamanlamasından doğar: bitiş bildirimi kuyruğa almadan önce ya da sonra gelebilir ve sonucu değiştirir.

## Hata ve İptal

Arka plan aktarımı da başarısız olabilir: sunucu yanıt vermeyebilir, bağlantı kopabilir ya da dosya yarıda kesilebilir. Başarısız görev temsilciye bir hatayla bildirilir. Bazı hatalarda sistem, kesilen yerden devam etmek için gereken veriyi hatanın içinde verir. Uygulama bu veriyi saklayıp görevi kaldığı yerden başlatırsa aynı baytlar yeniden indirilmez. Bunu yapmayan uygulama, yarım kalan büyük bir dosyayı baştan indirir.

Kullanıcı bir aktarımı iptal ettiğinde kayıt defterinden de çıkarılması gerekir. İptal edilen görev kayıtta kalırsa bir sonraki açılışta denetim onu sürüyor sanar ve yeniden kuyruğa almaz; kullanıcı iptal ettiği dosyanın ne zaman inmeye başladığını sorar ya da dosyanın hiç inmediğini görür. Bu, kaydın sistemin durumunu yansıtması gerektiği ilkesinin bir başka yüzüdür.

## Aktarılan Dosyanın Doğrulanması

İndirme bitti demek, dosyanın doğru olduğu demek değildir. Sunucu bir hata sayfasını başarılı bir yanıtla döndürmüş olabilir ya da dosya yarım kalmış olabilir. Taşımadan önce yanıtın durum kodu denetlenir, dosya boyutu beklenenle karşılaştırılır ve mümkünse bir özet değeri doğrulanır. Doğrulanmayan bir dosya kalıcı konuma alınırsa bozuk bir veri uzun süre fark edilmeden kalır. Kullanıcı bir video açtığında oynatılamadığını görür ve uygulamanın dosyayı neden bozuk indirdiğini anlayamaz.

## İlerlemeyi Göstermek

Arka plan aktarımı sürerken kullanıcı uygulamayı açabilir ve aktarımın durumunu görmek ister. Temsilci, indirilen bayt sayısını düzenli aralıklarla bildirir; uygulama bu bilgiyi bir ilerleme çubuğuna bağlar. Burada da kayıt defterinin tek doğruluk kaynağı olmadığı akılda tutulmalıdır: uygulama yeniden açıldığında ilerleme bilgisi sistemden yeniden sorulmalıdır, çünkü uygulama kapalıyken bildirilen baytlar kayıt defterine hiç ulaşmamıştır.

İlerleme bilgisi her zaman kesin değildir. Sunucu toplam boyutu bildirmiyorsa yüzde hesaplanamaz ve çubuk belirsiz bir göstergeye döner. Bu durumda uydurma bir yüzde göstermek kullanıcıyı yanıltır; "indiriliyor" demek daha dürüsttür. Aktarım tamamlandığında bildirim göndermek de yaygındır, ama bildirim izni kullanıcıya aittir ve uygulama bildirim gösteremeyeceği bir durumda da çalışmaya devam etmelidir.

## Ağ Koşullarına Bağlı Kısıtlar

Arka plan oturumunun yapılandırması, aktarımın hangi koşullarda yürüyeceğini de belirler. Yalnız kablosuz ağda indirmeyi, ucuz olmayan bağlantıda indirmeyi ya da şarj olurken indirmeyi seçmek mümkündür. Kısıt ne kadar sıkıysa aktarım o kadar geç başlar. Kullanıcıya büyük bir dosya vaat eden bir uygulama, bu koşulları açıkça bildirmelidir; aksi hâlde kullanıcı aktarımın neden başlamadığını anlayamaz.

Kısıtın sonucu ölçüme de yansır: aktarımın ne zaman biteceği bilinmediği için kayıt defteri uzun süre "sürüyor" durumunda kalabilir. Bu, hatalı bir kayıt değil, beklenen bir durumdur. Kaydın hata olarak okunması, kullanıcının aynı dosyayı yeniden kuyruğa almasına ve yinelenen aktarıma yol açar.

## Sık Yapılan Hatalar

- Yeniden açılışta listeyi sormadan kuyruğa almak. Sistemin sürdürdüğü aktarım çoğalır.
- İndirilen dosyayı temsilci yöntemi dönmeden taşımamak. Geçici konum silinir.
- Tanımlayıcıyı her açılışta farklı üretmek. Uygulama eski aktarımlara yeniden bağlanamaz.
- Arka plan oturumunda kapanışta tutulan değerlere güvenmek. Uygulama sonlandırılmış olabilir.
- Aktarımın ne zaman biteceğini kestirmek. Bu karar sistemindir.

## Ölçülen Sonucun Yorumu

Aynı iki yaklaşım aynı yeniden açılışta karşılaştırıldı ve farkı tek bir denetim yarattı: tanımlayıcıya bakmak. Dikkat edilirse kuyruğa alma işlemi hiçbir yerde hata vermedi; üç aktarım kaydı yasal bir durumdur. Yineleme sorunu, ağ derslerinde sık gördüğümüz gibi, sessizdir. Kayıt defterini tanımlayıcıyla tutmak, yinelemeyi çözen tek satırlık bir kural olarak göründü; ama bu kuralın çalışması için kaydın sistemin gerçek durumuyla uyumlu tutulması gerekir.

## Sınırlayıcı Ölçüm

Model hiçbir yerde sistemin aktarımı ne zaman bitireceğini ya da uygulamayı ne zaman uyandıracağını hesaplamaz. Aşağıdaki ölçümde bitme ve kuyruğa alma işlemleri iki sırada uygulanır; sıra modele dışarıdan verilir.

```swift
// main.swift — bitme ve kuyruga alma, iki sira
let running = Registry(tasks: ["a.zip"])
let race = replay("bitme-ve-kuyruk", from: running, finish("a.zip"), then: enqueueIfMissing(["a.zip"])).report()
countSensitivities([race])
```

```
bitme-ve-kuyruk | bir=[] iki=[] ab=[a.zip] ba=[] -> siraya-duyarli
saglam: 0
yinelemeye-duyarli: 0
siraya-duyarli: 1
cift-duyarli: 0
```

Sıra duyarlıdır: aktarım önce bitip sonra kuyruğa alınırsa kayıt dolu kalır; önce kuyruğa alınıp sonra biterse kayıt boşalır. Hangi sıranın gerçekleşeceği ise ölçülmez; modelde sıra bir girdidir, bir hesap değildir. **Kural işlemlerin sırasını görür ama sırayı kimin belirlediğini görmez.**

**AG18.** Sistemin aktarımı ne zaman sürdüreceği, uygulamayı ne zaman uyandıracağı ve hangi koşullarda erteleyeceği ölçülmedi. Bu davranış sistem koşullarına bağlıdır.

## Özet

- Arka plan oturumunda aktarımı sistem yürütür; uygulama sistem tarafından sonlandırılsa bile sürer.
- Yeniden açılışta listeyi denetlemeden yeniden kuyruğa almak sürmekte olan aktarımı çoğalttı.
- Görev tanımlayıcısına göre kayıt tutmak aynı yeniden açılışta sağlam kaldı.
- Bitme ve kuyruğa alma işlemlerinin sırası sonucu belirledi; sırayı belirleyen sistemdir ve ölçülmedi.
- Aktarım bitince sonucu bir temsilci alır ve dosya geçici konumdan taşınmalıdır.
- Bu dersin duyarlılığı: **yinelemeye duyarlı**.

## Sonraki Adım

Ağ katmanının altı dersi burada bitiyor. Sıradaki konuda ölçü, eşzamanlılık katmanına geçecek: aynı işin iki kez çalışmasının ve iki işin birbirine karışan sırasının, paylaşılan bir durumda neyi değiştirdiği ölçülecek.
