---
title: 'Paket Yöneticisi'
source: 'https://academia.sh/tr/kurslar/ios-platformu/paket-yoneticisi'
course: 'iOS Platformu ve Araçlar'
language: tr
updated: '2026-10-21T05:03:10+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'İki paketin aynı bağımlılık için istediği sürüm aralıklarının kesişimini ölçer'
    - 'Ayrık aralıkların neden reddedildiğini gösterir'
    - 'Yerel paketin uzak paketin yerini aldığını ve paket ürünlerinin birleştiğini ölçer'
    - 'Çözücünün kesişimden en yüksek sürümü seçtiğini ve kuralın seçilen sürümü saymadığını gösterir'
---

# Paket Yöneticisi

İki paketin aynı bağımlılık için istediği sürüm aralıklarının kesişiminin, yerel paketin uzak paketin yerini almasının ve paket ürünlerinin birleşiminin ölçümü.

Önceki ders yerel dosyaların ve anahtarların buluşmasını ölçtü. Bir uygulama yalnız kendi dosyalarından oluşmaz; başkalarının yazdığı kodu **paket (package)** olarak alır. Platformun **paket yöneticisi (package manager)** her paketin **bağımlılık (dependency)** listesini okur, bu bağımlılıkları indirir ve her biri için hangi sürümün kullanılacağına karar verir. Karar zor bir yerde çıkar: iki paket aynı üçüncü paketi ister ve her biri o paketin farklı sürümlerini kabul eder.

Ölçü ekseni değişmez: iki tanım buluşunca nasıl çözülüyor? Bu derste buluşan tanımlar paketlerin sürüm kısıtlarıdır. Bir sürüm kısıtı, kabul edilen sürümlerin bir kümesini anlatır; iki kısıt buluştuğunda sınıflandırıcı sonucun hangi çözüme düştüğünü söyler.

## Sınıflandırıcı

```swift
// Meeting.swift — iki tanim bulusunca nasil cozuldugunu siniflandirir
struct Meeting {
    let label: String
    let first: Set<String>
    let second: Set<String>
    let result: Set<String>?

    init(_ label: String, first: Set<String>, second: Set<String>, result: Set<String>?) {
        self.label = label
        self.first = first
        self.second = second
        self.result = result
    }

    var resolution: String {
        if first.isEmpty || second.isEmpty
            || first.isSubset(of: second) || second.isSubset(of: first) {
            return "olcum-disi"
        }
        guard let result, !result.isEmpty else { return "ret" }
        if result == first.union(second) { return "birlesim" }
        if result == first.intersection(second) { return "kesisim" }
        if result == first || result == second { return "oncelik" }
        return "kural-disi"
    }

    static func list(_ values: Set<String>) -> String {
        values.isEmpty ? "bos" : values.sorted().joined(separator: ",")
    }

    func report() {
        let outcome = result.map(Meeting.list) ?? "yok"
        print("\(label): ilk \(Meeting.list(first)) | ikinci \(Meeting.list(second)) | sonuc \(outcome) -> \(resolution)")
    }
}

func summarize(_ meetings: [Meeting]) {
    for resolution in ["oncelik", "kesisim", "birlesim", "ret"] {
        let count = meetings.filter { $0.resolution == resolution }.count
        print("\(resolution): \(count)")
    }
}
```

Bu derste sürüm kümelerini kurmak için küçük bir yardımcı daha gerekir. Kısıt, bir alt sınır ve bir üst sınırdan oluşur; alt sınır dâhil, üst sınır hariçtir. Yardımcı bir sürüm metnini sayılara ayırır, iki sürümü sırayla karşılaştırır ve bir kısıtın kabul ettiği sürümleri mevcut sürümler arasından süzer. Dosya yalnız tanım içerir, çıktısı yoktur.

```swift
// Requirement.swift — bir surum kisitinin kabul ettigi surumleri sayar
func versionKey(_ text: String) -> [Int] {
    text.split(separator: ".").compactMap { Int($0) }
}

func isBefore(_ left: String, _ right: String) -> Bool {
    versionKey(left).lexicographicallyPrecedes(versionKey(right))
}

struct Requirement {
    let from: String
    let upTo: String

    func accepts(_ version: String) -> Bool {
        !isBefore(version, from) && isBefore(version, upTo)
    }
}

func accepted(_ requirement: Requirement, among available: [String]) -> Set<String> {
    Set(available.filter { requirement.accepts($0) })
}

func rangeMeeting(_ label: String, _ first: Requirement, _ second: Requirement, available: [String]) -> Meeting {
    let left = accepted(first, among: available)
    let right = accepted(second, among: available)
    return Meeting(label, first: left, second: right, result: left.intersection(right))
}
```

## Sürüm Aralıkları

Paketler **anlamlı sürümleme (semantic versioning)** ile numaralanır: üç sayı, nokta ile ayrılmış. İlk sayı uyumsuz değişiklikte, ikincisi uyumlu yeni özellikte, üçüncüsü düzeltmede artar. Bir paket başka bir paketi istediğinde genellikle bir **sürüm aralığı (version range)** yazar: "bire eşit ya da büyük, ikiden küçük". Üst sınır, uyumsuz değişikliğin geldiği sürümden önce durur.

Paket tanımı `Package.swift` dosyasında yazılır. Dosya platformun paket tanım çerçevesini kullandığı için yalnız kaynak olarak durur. Bağımlılık satırı bir adres ve bir aralık taşır.

```swift
import PackageDescription

let package = Package(
    name: "Formatter",
    dependencies: [
        .package(url: "https://example.com/parser.git", "1.0.0"..<"2.0.0")
    ],
    targets: [
        .target(name: "Formatter", dependencies: [.product(name: "Parser", package: "parser")])
    ]
)
```

Bu dosya bir ölçüm sonucu üretmez. İkinci bir paket aynı bağımlılığı `"1.2.0"..<"3.0.0"` aralığıyla ister. İkisini ölçmek için paketin yayımladığı sürümleri sabit bir liste olarak alırız: `1.0.0` ile `2.1.0` arasında altı sürüm. Her aralık bu listeden süzülür ve iki kümenin buluşması sınıflandırıcıya verilir. Önce kesişen iki aralık, sonra ayrık iki aralık.

```swift
// main.swift — iki paketin ayni bagimlilik icin istedigi surum araliklari
let published = ["1.0.0", "1.1.0", "1.2.0", "1.3.0", "2.0.0", "2.1.0"]

let overlapping = rangeMeeting(
    "overlapping",
    Requirement(from: "1.0.0", upTo: "2.0.0"),
    Requirement(from: "1.2.0", upTo: "3.0.0"),
    available: published
)
let disjoint = rangeMeeting(
    "disjoint",
    Requirement(from: "1.0.0", upTo: "1.2.0"),
    Requirement(from: "2.0.0", upTo: "3.0.0"),
    available: published
)
overlapping.report()
disjoint.report()
```

```
overlapping: ilk 1.0.0,1.1.0,1.2.0,1.3.0 | ikinci 1.2.0,1.3.0,2.0.0,2.1.0 | sonuc 1.2.0,1.3.0 -> kesisim
disjoint: ilk 1.0.0,1.1.0 | ikinci 2.0.0,2.1.0 | sonuc bos -> ret
```

**GO9.** Ölçüm alt sınırı dâhil, üst sınırı hariç bir aralık biçimi için yapıldı. Tek sürüme sabitlenen kısıt ve yalnız alt sınır taşıyan kısıt ölçülmedi. Sürüm listesi yayımlanmış altı sürümle sınırlıdır.

İlk buluşmada iki aralığın ortak sürümleri `1.2.0` ve `1.3.0`: çözüm **kesişim**. İkinci buluşmada hiçbir ortak sürüm yok: sonuç boş ve çözüm **ret**. Platformun paket yöneticisi bu durumda çözümlemeyi durdurur ve hangi iki kısıtın çeliştiğini bildirir.

Ret bir hata değil, bir bilgidir. Bağımlılık listesinde çelişen iki kısıt vardır ve ikisinden birinin değişmesi gerekir. Paket yöneticisi hangisinin gevşetileceğini seçemez; bu karar paket yazarına aittir.

## Yerel Paket

Geliştirme sırasında bir bağımlılığı yayımlanmış sürümüyle değil, diskteki bir dizinle kullanmak mümkündür. Böyle bir **yerel paket (local package)** aynı ada sahip uzak paketin yerini alır. Platform yerel olanı seçer; uzak sürümü hiç indirmez. Bağımlılığın kaynağını değiştirip hemen sonucu görmek için yeni bir sürüm yayımlamaya gerek kalmaz.

Model bunu bir seçim işleviyle kurar: yerel kaynak varsa onu, yoksa uzak kaynağı döndürür. İki paket için ölçeriz: biri yerel olarak da bulunuyor, diğeri yalnız uzakta.

```swift
// main.swift — yerel paket ayni adli uzak paketin yerini alir
func chooseSource(remote: String, local: String?) -> String {
    local ?? remote
}

func sourceMeeting(_ label: String, local: String?) -> Meeting {
    let chosen = chooseSource(remote: "remote", local: local)
    return Meeting(label, first: ["remote"], second: local.map { [$0] } ?? [], result: [chosen])
}

let sourceMeetings = [
    sourceMeeting("parser-package", local: "local"),
    sourceMeeting("lexer-package", local: nil)
]
for meeting in sourceMeetings { meeting.report() }
```

```
parser-package: ilk remote | ikinci local | sonuc local -> oncelik
lexer-package: ilk remote | ikinci bos | sonuc remote -> olcum-disi
```

Yerel kaynak tanımlı olduğunda iki kaynak buluştu ve yerel olan kazandı: **öncelik**. Tanımlı olmadığında ikinci tanım boştu ve ortada bir buluşma yoktu. Aynı ad iki kaynakta bulunduğunda uzak sürümün kısıtları da devre dışı kalır; yerel paket hangi sürümde olursa olsun kabul edilir. Bu yüzden unutulmuş bir yerel paket, kısıtların beklenmedik biçimde göz ardı edilmesine yol açabilir.

**GO10.** Ölçüm iki kaynak çeşidini, yerel ve uzak olanı karşılaştırdı. İki farklı uzak adresin aynı paket adını taşıdığı durum ölçülmedi.

## Paket Ürünleri

Bir paket yalnız kodunu değil, **ürün (product)** adı verilen bağlanabilir çıktıları da bildirir: bir kütüphane, bir çalıştırılabilir dosya. Uygulama hedefi bağlanacak ürünleri adıyla seçer. İki paketin ürünleri uygulama için tek bir kullanılabilir ürün kümesi oluşturur. Bir ürün adını iki paket de sunuyorsa küme o adı iki kez taşımaz.

Model iki paketin ürün kümesinin birleşimini alır. Birinci paket `parser` ve `tokens` ürünlerini, ikinci paket `formatter` ve `tokens` ürünlerini sunar.

```swift
// main.swift — iki paketin urunleri tek kumede birlesir
func availableProducts(_ first: Set<String>, _ second: Set<String>) -> Set<String> {
    first.union(second)
}

let parserProducts: Set<String> = ["parser", "tokens"]
let formatterProducts: Set<String> = ["formatter", "tokens"]

let productMeeting = Meeting(
    "products",
    first: parserProducts,
    second: formatterProducts,
    result: availableProducts(parserProducts, formatterProducts)
)
productMeeting.report()
```

```
products: ilk parser,tokens | ikinci formatter,tokens | sonuc formatter,parser,tokens -> birlesim
```

Üç ürün çıktı ve çözüm **birleşim**. Ortak `tokens` adı çakışma doğurmadı, çünkü bu ölçümde ürün adı bir kimliktir ve küme aynı kimliği iki kez saymaz. Gerçek bir projede iki ayrı paketin aynı adı taşıyan iki farklı ürünü olması başka bir sorundur; model bu durumu ayırt etmez.

**GO11.** Ölçüm ürün adını kimlik olarak ele aldı. Aynı adı taşıyan iki farklı ürünün çakışması ve bir ürünün yalnız belirli bir platformda sunulması ölçülmedi.

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

İlk ölçümde kesişim iki sürüm verdi: `1.2.0` ve `1.3.0`. Uygulama ise tek bir sürümle derlenir. Çözücü kesişimden bir sürüm seçer ve genellikle en yüksek olanı seçer; seçilen sürüm bir kilit dosyasına yazılır ve sonraki çözümlemelerde yeniden kullanılır. Aynı buluşmaya bir kez kabul edilen kümeyi, bir kez de seçilen sürümü sonuç olarak verelim.

```swift
// main.swift — cozucu kesisimden en yuksek surumu secer
func highest(_ versions: Set<String>) -> String {
    versions.max { isBefore($0, $1) } ?? "none"
}

let catalog = ["1.0.0", "1.1.0", "1.2.0", "1.3.0", "2.0.0", "2.1.0"]
let firstRange = Requirement(from: "1.0.0", upTo: "2.0.0")
let secondRange = Requirement(from: "1.2.0", upTo: "3.0.0")
let leftSet = accepted(firstRange, among: catalog)
let rightSet = accepted(secondRange, among: catalog)
let commonSet = leftSet.intersection(rightSet)

let acceptedSet = Meeting("accepted-set", first: leftSet, second: rightSet, result: commonSet)
let chosenVersion = Meeting("chosen-version", first: leftSet, second: rightSet, result: [highest(commonSet)])
acceptedSet.report()
chosenVersion.report()
```

```
accepted-set: ilk 1.0.0,1.1.0,1.2.0,1.3.0 | ikinci 1.2.0,1.3.0,2.0.0,2.1.0 | sonuc 1.2.0,1.3.0 -> kesisim
chosen-version: ilk 1.0.0,1.1.0,1.2.0,1.3.0 | ikinci 1.2.0,1.3.0,2.0.0,2.1.0 | sonuc 1.3.0 -> kural-disi
```

Kabul edilen küme verildiğinde çözüm kesişim; çözücünün seçtiği tek sürüm verildiğinde ise sınıflandırıcı `kural-disi` yazdı. Tek sürüm ne iki kümenin birleşimidir ne kesişimidir ne de birinin kendisidir. Kural yalnız kabul edilen kümeyi tarif eder; o kümeden hangi öğenin seçileceği ayrı bir karardır.

Pratik sonuç: kısıtlar çözümlenebilir göründüğünde bile uygulamanın hangi sürümle derleneceğini kısıtlar değil, çözücünün seçim kuralı ve kilit dosyası belirler. Kilit dosyası olmadan yapılan yeni bir çözümleme daha yüksek bir sürüm seçebilir; kısıtlar bunu yasaklamaz, çünkü seçilen sürüm hâlâ kesişimin içindedir.

**GO12.** Model seçimi her zaman en yüksek sürüm olarak aldı. Çözücünün kilit dosyasındaki bir sürümü koruduğu durum ölçülmedi.

## Özet

- İki paketin aynı bağımlılık için istediği sürüm aralıkları, kabul edilen sürüm kümelerinin kesişimiyle çözülür.
- Ortak sürümü olmayan ayrık aralıklar reddedilir ve çözümleme durur.
- Yerel paket aynı adlı uzak paketin yerini alır; yerel kaynak yoksa buluşma doğmaz.
- İki paketin ürünleri uygulamanın kullanabileceği ürün kümesinde birleşir.
- Bu dersin çözümü: **kesişim**. Kural kabul edilen kümeyi sayar, çözücünün seçtiği tek sürümü saymaz.

## Sonraki Adım

Bu derste paketlerin kısıtları buluştu ve ortak bir sürüm kümesi çıktı. Uygulama derlendikten sonra bir yerde çalışmak zorundadır: geliştirme sırasında bu yer çoğunlukla simülatördür, ama gerçek aygıtın kabul ettiği her şeyi simülatör kabul etmez. Bir sonraki ders uygulamanın gerektirdiği yeteneklerle simülatörün sunduğu yeteneklerin buluşmasını ölçer.
