<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[TalentKit - Medium]]></title>
        <description><![CDATA[TurkishKit; Apple platformlarında kodlama, tasarım ve yaratıcılık alanlarında eğitici dijital içerikler yayınlar, etkinlik ve eğitimler düzenler. - Medium]]></description>
        <link>https://medium.com/turkishkit?source=rss----19443271f3c7---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>TalentKit - Medium</title>
            <link>https://medium.com/turkishkit?source=rss----19443271f3c7---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 12 Nov 2026 20:24:37 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/turkishkit" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Xcode: Workspace, Project, Targets & Schemes.]]></title>
            <link>https://medium.com/turkishkit/xcode-workspace-project-targets-schemes-ddca60449403?source=rss----19443271f3c7---4</link>
            <guid isPermaLink="false">https://medium.com/p/ddca60449403</guid>
            <category><![CDATA[xcworkspace]]></category>
            <category><![CDATA[target]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[scheme]]></category>
            <category><![CDATA[xcode]]></category>
            <dc:creator><![CDATA[tugran]]></dc:creator>
            <pubDate>Sat, 11 May 2024 15:42:44 GMT</pubDate>
            <atom:updated>2024-05-11T15:43:43.294Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zMeTilzqDFMHEZDXfHh3dw.png" /></figure><p>Merhaba TurkishKit okuyucuları! 👋🏻 Bugünkü yazımızda Xcode içerisinde uygulama geliştirirken sıkça karşımıza çıkan Workspace, Project, Targets ve Schemes kavramlarından bahsedeceğiz. Hazırsanız başlayalım!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*wugc3kbELGCvoJdTvhSDUw.png" /><figcaption>Katmansal gösterim.</figcaption></figure><p>Yukarıda da gördüğünüz üzere, Workspace içerisinde sanılanın aksine birden fazla Project dosyası bulunabilir. Project içerisinde de yine aynı şekilde birden fazla Targets dosyası bulunabilir ve bu da bize esneklik, kod paylaşma ve yeniden kullanma gibi seçenekler sağlar.</p><h3>👩🏼‍💻 Workspace:</h3><p>Workspace, Xcode projelerinizi, birlikte çalıştırılabilir hale getiren ve birbirleriyle ilişkili projeleri bir araya getiren bir yapıdır. Workspace içinde birden fazla Xcode projesini veya framework’ü barındırabilirsiniz. Örneğin, bir iOS uygulaması ve onunla birlikte kullanılacak bir framework varsa, bunları tek bir workspace içine yerleştirebilirsiniz.</p><h3>🔨 Project:</h3><p>Project, Xcode’da tek bir uygulama veya framework’ün kaynak kodunu, kaynak dosyalarını, kaynak dosyalarını düzenlemek, derlemek ve yapılandırmak için kullanılan ana yapıdır. Her Xcode projesi, kendine özgü bir .xcodeproj dosyasına sahiptir. Ayrıca, Project dosyası, projenin yapılandırması, dosya düzeni, targetler ve düzenleme seçenekleri gibi önemli bilgileri içerir. Bu dosya, geliştiricilere projenin genel yapısını ve ayarlarını yönetme imkanı sunar. Projeyi başka bir geliştiriciyle paylaşırken veya farklı bir bilgisayara taşırken, .xcodeproj dosyası projenin tüm yapılandırmasını ve ayarlarını kolayca taşımak için kullanılır.</p><h3>🎯 Targets:</h3><p>Targets (hedefler), projenin farklı yapılandırmalarını, platformlarını veya test durumlarını temsil eder. Her bir target <strong>en az bir</strong> <strong>scheme</strong> içerir. Projenize target eklemek için şu adımları izleyebilirsiniz:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*RsLq8zSNMDozFn4aI5bDUA.gif" /><figcaption>Target ekleme.</figcaption></figure><p>Bir Xcode projesinde, genellikle birden fazla target bulunabilir. Projenizi ayrı targetlara ayırmak, uygulamanızı daha iyi yönetme ve geliştirme esnekliği sağlar.</p><p>Her target, belirli bir versiyonun veya yapılandırmanın özelliklerini ve yapılandırmasını içerir. Bu sayede, uygulamanızın versiyonları arasındaki farklılıkları daha iyi yönetebilirsiniz. Örneğin, ücretli sürümde premium özellikler veya reklamsız deneyim gibi ekstra özellikler sağlayabilirken, ücretsiz sürümde temel işlevselliği koruyabilirsiniz.</p><h4>Yukarıda verdiğimiz örneği pratiğe dökelim 👨🏻‍🔧</h4><ol><li>Var olan target dosyamızı ücretsiz versiyon olarak isimlendirelim ve aşağıdaki gibi ücretli versiyon için bir target oluşturalım.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/492/1*8OMD5-Lv9NJaxIX6FQs7LQ.png" /></figure><p>2. <strong>appFREE</strong> targetimizin <strong>Build Setting</strong> sekmesine tıklayalım. Ardından <strong>Other Swift Flags</strong> kısmına gelip targetimize <strong>“-DFREE”</strong> şeklinde flag ekleyelim. Aynı işlemi appPRO için de <strong>“-DPRO”</strong> olarak yapalım.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*bAukI4YKWYh2XODDSI3zLQ.gif" /><figcaption>(Siz de kendi değerlerinizi verirken “-D” ön ekini unutmayın)</figcaption></figure><p>Ardından <strong>ViewController</strong> dosyamıza gidip durum kontrolüne göre çalışan kodumuzu yazalım.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*detVtynZv0jJlSz9DBoCxw.png" /></figure><p>Uygulamamızın ücretsiz versiyonu çalışıyor ise konsolda “Ücretsiz versiyon” eğer ücretli ise “Ücretli versiyon” çıktısını alacağız. Peki targetlerimizi nasıl çalıştıracağız 🤔</p><p>Devamı <strong>⚙️ Schemes</strong> kısmında ⬇️</p><h3>⚙️ Schemes:</h3><p>Şemalar (schemes), Xcode projenizin nasıl derleneceğini, çalıştırılacağını veya test edileceğini belirten yapılandırmalardır. Her bir şema, projenin belirli bir amaç için nasıl yapılandırılacağını tanımlar. Örneğin, bir şema, uygulamanızı derlemek ve simülatörde çalıştırmak için yapılandırılabilir; başka bir şema ise uygulamanızı derlemek ve cihazda test etmek için yapılandırılabilir. Targetinize yeni bir <strong>scheme</strong> eklemek için şu adımları izleyebilirsiniz:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*AFzkOfJPLwyBl6yzlnBFhg.gif" /><figcaption>Eklenilen her target kendi isminde bir scheme içerir.</figcaption></figure><p>Şimdi, <strong>appFREE</strong> targetimizin scheme’i olan <strong>app</strong> scheme’i çalıştıralım ve konsolda “Ücretsiz versiyon” çıktısını alalım. Ardından appPRO targetimizin scheme’i olan <strong>appPRO</strong> scheme’i çalıştıralım ve konsolda “Ücretli versiyon” çıktısını alalım</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/1*OysaKsZ4gtcntuRhoFpSfQ.gif" /></figure><blockquote>Unutmayın! Çalıştırdığımız şeyler target değil, o targetlerin scheme dosyaları.</blockquote><p>Böylece yazımızın sonuna geldik. Artık Workspace, Project, Targets ve Schemes kavramlarının ne anlama geldiğini öğrenmiş olduk. Görüşmek üzere, keyifli kodlamalar. 👩‍💻</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ddca60449403" width="1" height="1" alt=""><hr><p><a href="https://medium.com/turkishkit/xcode-workspace-project-targets-schemes-ddca60449403">Xcode: Workspace, Project, Targets &amp; Schemes.</a> was originally published in <a href="https://medium.com/turkishkit">TalentKit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Async & Await]]></title>
            <link>https://medium.com/turkishkit/async-await-924e97356a48?source=rss----19443271f3c7---4</link>
            <guid isPermaLink="false">https://medium.com/p/924e97356a48</guid>
            <category><![CDATA[asyncawait]]></category>
            <category><![CDATA[gcd]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[concurrency]]></category>
            <category><![CDATA[i̇leri-swift]]></category>
            <dc:creator><![CDATA[Ufuk Köşker]]></dc:creator>
            <pubDate>Sat, 11 May 2024 15:35:45 GMT</pubDate>
            <atom:updated>2024-05-11T15:35:45.630Z</atom:updated>
            <content:encoded><![CDATA[<h4>Swift’te Asenkron Programlamayı Basitleştiren Yapısal Yaklaşım: Async/await</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*CLi2uYmney7KoOevWdFq_g.png" /></figure><p>Swift geliştirme süreci, clouser ve completion işlevlerini kullanarak asenkron programlama yapabiliriz. Ancak, yapıların kullanımı zorlayıcı olabilir. Neyse ki, Swift 5.5&#39;in getirdiği yeniliklerle birlikte Xcode 13, async/await yapısını tanıtarak yapılandırılmış bir şekilde asenkron ve paralel kod yazmayı sağlayan yerleşik bir destek sundu.</p><p>Async/await yapısı, geliştiricilere clouser ve completion işlevlerini kullanmadan asenkron kod yazma imkanı sunar. Bu da Swift’teki karmaşık asenkron kodun okunabilirliğini artırırken, aynı zamanda geliştirme sürecini daha verimli hale getirir.</p><h3>Async ve Await: Yeni Olanaklar</h3><ul><li><strong>async:</strong> Bu anahtar kelime, bir işlevin veya özelliğin asenkron olduğunu belirtir. Kodun akışını, bir asenkron işlevin bir değer döndürmesini beklerken askıya alır.</li><li><strong>await:</strong> Bu anahtar kelime, kodun bir asenkron işlevin dönüşünü beklerken yürütmesini durdurabileceğini belirtir.</li></ul><blockquote>Completion İşlevi yapılandırılmamışken, async-await yapısı yapılandırılmış sıralı deseni takip eder. Aşağıdaki kod örnekleri, sırasıyla clouser’ların yapılandırılmamış ve yapılandırılmış desenlerini göstermektedir.</blockquote><p>Async-await işlevi yapılandırılmış eşzamanlılık sağlar ve bu nedenle Swift’teki karmaşık asenkron kodun okunabilirliğini artırır. Aşağıdaki kod örneğinde async-await kullanımını görebilirsiniz.</p><pre>func fetchThumbnail(for url: URL) async throws -&gt; UIImage { // 1. Yöntemi çağır<br>    // 2. URL&#39;den görüntüleri al ve görüntüyü döndür<br>    let (data, response) = try await URLSession.shared.data(from: url)<br>    // 3. Yanıt durum kodu başarılı değilse hata fırlat<br>    guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw ARError.badID }<br>    // 4. Yanıt verisinden Görüntü oluştur<br>    let image = UIImage(data: data)<br>    // 5. Görüntüyü yeniden boyutlandır ve döndür<br>    // 6. Geçersiz görüntü ise hata fırlat<br>    guard let thumbnail = await image?.byPreparingThumbnail(ofSize: CGSize(width: 300, height: 300)) else { throw ARError.badImage }<br>    // 7. Geçerli görüntüyü döndür<br>    return thumbnail<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*H2FkV9JB7HCHAhKQFCJ6cg.jpeg" /></figure><p>Aşağıda görebileceğiniz gibi, çağrı yöntemi, completion işlevi kullanarak görüntüler alınmadan önce döner. Sonuç alındığında, completion’a geri döneriz. Bu yapılandırılmamış bir işlem sırasıdır ve takip etmesi zordur. Eğer completion callback içinde başka bir asenkron yöntem gerçekleştirseydik, başka bir clouser eklenirdi. Her clouser, işlem sırasını takip etmeyi daha da zorlaştırır, çünkü her seviye için bir girinti ekler.</p><pre>func fetchThumbnail(for url: URL, completion: @escaping(UIImage?, Error?) -&gt; Void) {<br>        // 1. Fonksiyon çağırılır.<br>        let task = URLSession.shared.dataTask(with:url) { data, response, error in // 4. Asenkron yöntem döner<br>            <br>            if let error = error {<br>                // 5. Herhangi bir hata gelirse, tamamlama bloğu hatayla birlikte döner<br>                completion(nil, error)<br>            } else if (response as? HTTPURLResponse)?.statusCode != 200 {<br>                // 6. Yanıt durum kodu başarılı değilse, tamamlama bloğu hatayla birlikte döner<br>                completion(nil, ARError.badID)<br>            } else {<br>                guard let image = UIImage(data: data!) else {<br>                    // 7. Geçerli bir resim değilse, tamamlama bloğu hatayla birlikte döner<br>                    completion(nil, ARError.badImage)<br>                    return<br>                }<br>                image.prepareThumbnail(of: CGSize(width: 300, height: 300)) { thumbnail in<br>                    guard let thumbnail = thumbnail else {<br>                        // 8. Yeniden boyutlandırıldıktan sonra geçerli bir resim değilse, tamamlama bloğu hatayla birlikte döner<br>                        completion(nil, ARError.badImage)<br>                        return<br>                    }<br>                    // 9. Geçerli resim, tamamlama bloğu resim nesnesiyle birlikte döner<br>                    completion(thumbnail, nil)<br>                }<br>            }<br>        }<br>        // 2. Veri görevini devam ettir<br>        task.resume()<br>    }<br>    // 3.Çağırma yöntemi çıkar</pre><h4>Tasks Nedir?</h4><p>Tüm asenkron fonksiyonlar, bir görevin parçası olarak çalışır. Bir fonksiyon asenkron bir çağrı yaparsa, çağrılan fonksiyon hala aynı görevin bir parçası olarak çalışır (ve çağrıcı, dönmesini bekler). Benzer şekilde, bir fonksiyon asenkron bir çağrıdan döndüğünde, çağrıcı aynı görevde çalışmaya devam eder. Asenkron kod doğrudan senkron yöntemden çağrılamaz. Senkron yöntemden asenkron kodu çağırmak için, bir görev oluşturup asenkron fonksiyonu ondan çağırmamız gerekir. Bu, senkron/asenkron kod arasında bir köprü oluşturur. Görev, asenkron işleri ayrı bir iş parçacığında yürütmek ve yönetmek için bir ortam oluşturur. Görev türü aracılığıyla asenkron kodu çalıştırabilir, duraklatabilir ve iptal edebiliriz.</p><pre>Task {<br>    let resultImage = try await fetchThumbnail(for: imageURL)<br>    ... // futher work<br>    ... // take over (asynchronously)<br>}</pre><p>Görev oluştururken, görevin ne kadar acil olduğuna bağlı olarak önceliği belirtmek önemlidir. Göreve doğrudan bir öncelik atayabilirsiniz, ancak atamazsanız Swift otomatik olarak önceliği belirlemek için üç kural izleyecektir:</p><ul><li>Eğer görev başka bir görevden oluşturulmuşsa, alt görev ana görevin önceliğini miras alacaktır.</li><li>Eğer yeni görev doğrudan ana iş parçacığından bir görev oluşturulmuşsa, kullanıcı tarafından başlatılan en yüksek öncelik ataması otomatik olarak atanır.</li><li>Eğer yeni görev başka bir görev veya ana iş parçacığı tarafından oluşturulmadıysa, Swift önceliği sorgulamaya çalışacaktır.</li></ul><p>En düşük öncelik <strong>background</strong>’dadır., burada işlem kullanıcının bakış açısından çok acil değildir. En yüksek öncelik yüksek olan, kullanıcı tarafından önemli olarak kabul edilen görevi ifade eden <strong>userInitiated</strong> ile eşanlamlıdır. Varsayılan öncelik orta düzeydedir, burada diğer işlemlerle aynı şekilde işlenir.</p><h4><strong>Eşzamanlı Olarak Birden Fazla Asenkron Fonksiyonu Çalıştırma</strong></h4><p>Eğer birden fazla ilişkisiz asenkron fonksiyonu eşzamanlı olarak çalıştırmak istiyorsak, onları kendi görevlerine sarabiliriz ve bu görevler eşzamanlı olarak çalışacaktır. Onların çalışma sırası belirsizdir.</p><pre>Task(priority: .medium) {<br> let result1: UIImage = try await fetchThumbnail(for: profileURL)<br>}<br><br>Task(priority: .medium) {<br> let result2: UIImage = try await fetchThumbnail(for: profileThumbnailURL)<br>}<br><br>Task(priority: .medium) {<br> let result3: UIImage = try await fetchThumbnail(for: productImageURL)<br>}</pre><h4><strong>Eşzamanlı Bağlama ile Birden Fazla Asenkron İşlemi Paralel Olarak Çalıştırma</strong></h4><p>Birden fazla asenkron işlemi paralel olarak çalıştırabilir ve sonuçları aynı anda alabiliriz. Bu, ayrıca eşzamanlı bağlama olarak da adlandırılır.</p><pre>Task(priority: .medium) {<br>    do {<br><br>        async let image1 = try await fetchThumbnail(for: productImageURL1)<br>        <br>        async let image2 = try await fetchThumbnail(for: productImageURL2)<br>        <br>        async let image3 = try await fetchThumbnail(for: productImageURL3)<br>        <br>        let imagesArray = try await [image1, image2, image3]<br>        <br>    } catch {<br>        // Handle Error<br>    }<br>}</pre><h4><strong>Asynchronous Sequences(Asenkron Diziler)</strong></h4><p>Swift 5.5&#39;in yeni <strong>Asynchron</strong> sistemi, asenkron diziler ve yineleyicilerin konseptini tanıtıyor. Bir AsyncSequence, Sequence türüne benzer — adım adım ilerleyebileceğiniz bir değer listesi sunar — ve asenkronluğu ekler. Bir dizi, ilk kullandığınızda tüm, bazı veya hiçbir değeri bulunmayabilir. Bunun yerine, değerler kullanıma hazır olduğunda almak için beklemeyi kullanırsınız.</p><pre>for await i in Counter(howHigh: 10) {   <br>  print(i, terminator: &quot; &quot;)<br>}</pre><p>AsyncSequence, Sequence’in asenkron bir türevidir ve AsyncSequence sadece bir protokoldür. AsyncSequence protokolü, bir AsyncIterator sağlar ve değerlerin geliştirilmesi ve potansiyel olarak depolanmasıyla ilgilenir. Asenkron yinelemeler oluştururken, AsyncSequence protokolüne uymalı ve makeAsyncIterator yöntemini uygulamalıyız.</p><pre>struct ImageURL: AsyncSequence {<br>    typealias Element = URL<br>    var urlStr: [String]<br><br>    func makeAsyncIterator() -&gt; ImageURLData {<br>        ImageURLData(urls: urlStr)<br>    }<br>}<br><br>struct ImageURLData: AsyncIteratorProtocol {<br>    var urls: [String]<br>    fileprivate var index = 0<br><br>    mutating func next() async throws -&gt; URL? {<br>        guard index &lt; urls.count else {<br>                    return nil<br>        }<br>        let filePath = urls[index]<br>        index += 1<br><br>        if let strURL = URL(string: &quot;https://image.tmdb.org/t/p/w500/\(filePath)&quot;) {<br>            return strURL<br>        }<br>        return nil<br>    }<br>}<br><br>private func getImages() {<br>    let imagesFilePath = [&quot;cOF0InT1qQVUeNjqxjF7gtEtL5L.jpg&quot;, &quot;hT3OqvzMqCQuJsUjZnQwA5NuxgK.jpg&quot;, &quot;8DwrHSpilQiZiegR9T8Q69ey8ru.jpg&quot; ]<br>    <br>    Task {<br>        var images: [UIImage] = [UIImage]()<br>        for try await filePath in ImageURL(urlStr: imagesFilePath) {<br>            do {<br>                async let (image_1) =   UIImage().fetchThumbnail(for: filePath)<br>                try await images.append(image_1)<br>            } catch {<br>                print(error)<br>            }<br>        }<br>    }<br>}</pre><h4><strong>Asenkron Özellikler</strong></h4><p>Bir özelliği asenkron hale getirebiliriz, bunun için özelliğin getter’ının ardından async eklememiz gerekmektedir.</p><pre>extension UIImage { <br>   // async property <br>   var thumbnail: UIImage? {<br>     get async { <br>         let size = CGSize(width: 300, height: 300) <br>         return await self.byPreparingThumbnail(ofSize: size)<br>       }<br>   }<br>}</pre><blockquote>Sadece salt okunur özellikler asenkron olabilir, bu özellik için açıkça bir setter oluşturmamız gerekmektedir. Eğer asenkron bir özelliğe setter sağlamaya çalışırsak, derleyici bir hata verecektir.</blockquote><h4>Throws İle Asenkron Özellikler</h4><p>Asenkron özellikler ayrıca throws anahtar kelimesini destekler. Bir özellik tanımında async anahtar kelimesinden sonra throws anahtar kelimesini eklememiz ve hatayı fırlatan yöntemle try await kullanmamız gerekmektedir.</p><pre>extension UIImage { <br>   var posterImage: UIImage {<br>      get async throws {<br>     do {<br>        let ( data, _) = try await URLSession.shared.data(from: imageUrl)<br>         return UIImage(data: data)!<br>       } catch {<br>           throw error<br>         }<br>      }<br>   }<br>}</pre><h4>Asenkron İçinde defer Kullanımı</h4><p>defer bloğu, fonksiyondan çıkarken en son çalışan koddur ve kaynak temizliğinin gözden kaçırılmadığından emin olmak için yürütülmesi garanti edilir.</p><pre>private func getMovies() {<br>  defer {<br>    print(&quot;Defer statement outside async&quot;)<br>  }<br>  Task {<br>     defer { <br>        print(&quot;Defer statement inside async&quot;)<br>    }<br>    let result = try? await     ARMoviesViewModel().callMoviesAPIAsyncAwait(ARMovieResponse.self)<br>    switch result {<br>       case .failure(let error): print(error.localizedDescription)<br>       case .success(let items): movies = items.results<br>       case .none: print(&quot;None&quot;)<br>    }<br>   print(&quot;Inside the Task&quot;)<br>  }<br> print(&quot;After the Task&quot;)<br>}<br>// After the Task<br>// Defer statement outside async<br>// Inside the Task<br>// Defer statement inside async</pre><h4>Continuation async APIs</h4><p>Eski kod, bazı işler tamamlandığında bizi bilgilendirmek için tamamlama işleyicilerini kullanır. Ancak bunu bir asenkron işlevden kullanmak zorunda kalacağımızda — üçüncü taraf kütüphanesi veya kendi işlevlerimiz için olsun — ancak bunu asenkron hale getirmek çok çalışma gerektirebilir. Devamı sayesinde, tamamlama işleyicilerini asenkron API’lerine sarabiliriz. Kullanılabilir birkaç türde devam mevcuttur:</p><ul><li>withCheckedThrowingContinuation</li><li>withCheckedContinuation</li><li>withUnsafeThrowingContinuation</li><li>withUnsafeContinuation</li></ul><pre>func getMoviesPostersAPI(_ movie: ARMovie, completion: @escaping PostersCompletionClosure) {<br>        let reviewURL = checkURL(ARAPI.moviePosters, movie)<br>        guard let url = reviewURL else {<br>            completion(nil, ARNetworkError.invalidUrl)<br>            return<br>        }<br>        ARNetworkManager().executeRequest(url: url, completion: completion)<br>    }<br>    <br>    func allPosters(_ movie: ARMovie) async -&gt; (ARMoviePoster?, Error?) {<br>        await withCheckedContinuation { continuation in<br>            getMoviesPostersAPI(movie) { posters, error in<br>                continuation.resume(returning: (posters, error))<br>            }<br>        }<br>    }</pre><blockquote>Devamı yalnızca tam olarak bir kez devam ettirilmelidir. Sıfır kez değil, iki veya daha fazla kez değil tam olarak bir kez.</blockquote><h4>async-await’ın Avantajları</h4><ul><li>İç içe geçmiş kapanışlarla oluşan “Doom Piramidi” probleminden kaçınma</li><li>Kodun azaltılması</li><li>Daha okunabilir olması</li><li>async/await ile güvenlik, bir sonuç garantilenirken tamamlama blokları çağrılabilir veya çağrılmayabilir.</li></ul><h3>Sonuç</h3><p>Swift 5.5 ve Xcode 13 ile gelen async/await yapısı, Swift geliştirme sürecini daha kolay ve verimli hale getiriyor. Yapılandırılmış asenkron programlama sayesinde, karmaşık asenkronik kodlar daha okunabilir ve yönetilebilir hale geliyor. Bu da geliştiricilere daha etkili ve güçlü uygulamalar oluşturma imkanı sunuyor.</p><p>Bizi daha yakından takip etmek istiyorsanız, sosyal medya hesaplarımıza aşağıdan ulaşabilirsiniz!</p><p><a href="https://twitter.com/turkishkit"><strong>Twitter</strong></a><strong> | </strong><a href="https://www.instagram.com/turkish.kit/"><strong>Instagram</strong></a><strong> | </strong><a href="https://www.facebook.com/turkishkit"><strong>Facebook</strong></a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*k1_P7JIx8OsZwkDD12uzJg.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=924e97356a48" width="1" height="1" alt=""><hr><p><a href="https://medium.com/turkishkit/async-await-924e97356a48">Async &amp; Await</a> was originally published in <a href="https://medium.com/turkishkit">TalentKit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[UIButton Configuration]]></title>
            <link>https://medium.com/turkishkit/uibutton-configuration-515751277c4b?source=rss----19443271f3c7---4</link>
            <guid isPermaLink="false">https://medium.com/p/515751277c4b</guid>
            <category><![CDATA[uibuttonconfiguration]]></category>
            <category><![CDATA[uikit]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[uibutton]]></category>
            <dc:creator><![CDATA[Ufuk Köşker]]></dc:creator>
            <pubDate>Sat, 11 May 2024 15:34:44 GMT</pubDate>
            <atom:updated>2024-05-11T15:34:44.559Z</atom:updated>
            <content:encoded><![CDATA[<h4>UIButton.Configuration ile Buton Özelleştirmenin Gücü</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ltlSiJuECm8x0xHc7uNgIw.png" /></figure><p>Button, iOS uygulamalarında temel bir öğedir. UIKit kullanarak bir uygulama geliştiriyorsanız, muhtemelen buton oluşturmak için UIButton sınıfını kullanırsınız. Bir buton oluşturmak basit bir süreçtir, ancak özelleştirmeler devreye girdiğinde istediğiniz sonuca ulaşmak zor olabilir. Birçoğumuz bunu yaşadık ve bu konuda çözümler aradık. Yalnız değilsiniz. Neyse ki, iOS 15.0 bize <strong>UIButton.Configuration</strong> kullanarak butonları özelleştirmeyi çok daha kolay hale getiriyor. Başlayalım!</p><h4>UIButton’da Yapılandırma Çeşitleri</h4><p>UIButton.Configuration dört farklı türde gelir: plain, filled, gray, and tinted. Bu makalede, sadece filled yapılandırmaya odaklanacağız. Diğer yapılandırmaları denemeniz için size bırakıyorum.</p><pre>var configuration = UIButton.Configuration.filled()</pre><h4>UIButton’da Title Ayarlama</h4><p>Bir title ayarlamak, yapılandırmanın title özelliğini kullanarak yapılır.</p><pre>configuration.title = &quot;Start download&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/518/1*zTHmRHP6pYDdYuLZEeUDKg.jpeg" /></figure><h4>UIButton’da Subtitle Ayarlama</h4><p>Yine, bir alt başlık ayarlamak için yapılandırmanın subtitle özelliğini kullanabiliriz. Configuration API olmadan alt başlık ayarlamak zor olurdu.</p><pre>configuration.subtitle = &quot;(Downloads a random image)&quot;</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/732/1*NVxoG41MA8cx1HfNREp_Tw.jpeg" /></figure><h4>UIButton Üzerine Image Ekleme</h4><p>Button’a bir görüntü eklemek ve özelleştirmek artık çok kolay. Burada dikkat edilmesi gereken önemli bir nokta, görüntünün dilin yönünü dikkate almasıdır.</p><pre>configuration.image = UIImage(systemName: &quot;arrow.down.square.fill&quot;)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/876/1*6EyrwpC4gkrjlUjYibuy4Q.jpeg" /></figure><h4>UIButton Üzerindeki Image ve Title Arasındaki Boşluk Ayarı</h4><p>UIButton yapılandırması, bir görüntü ile düğme arasında bir boşluk ayarlamayı kolaylaştırır.</p><pre>configuration.imagePadding = 20</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/869/1*Bw8IIDG_u1gtKRydu2iDAg.jpeg" /></figure><h4>UIButton’da Image’in Konumunu Değiştirme</h4><p><strong>imagePlacement</strong> özelliği favorimdir. iOS 15.0 öncesinde, yalnızca bir görüntünün konumunu değiştirmek için bir UIButton’da birçok kötü hack yazdım. <strong>imagePlacement</strong> özelliği aşağıdaki seçenekleri destekler: leading (ön), trailing (arka), top (üst) veya bottom (alt).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/872/1*I94Z3IgGG6p6VZpCbxOlhA.jpeg" /></figure><p>Bu makalede, <strong>UIButton.Configuration</strong>’un temel özelliklerini inceledik ve butonları özelleştirmenin modern ve etkili yollarını keşfettik. <strong>UIButton.ConfigurationUpdateHandler</strong> hakkında daha fazla bilgi için ayrı bir makaleyi bekleyin.</p><p>Bizi daha yakından takip etmek istiyorsanız, sosyal medya hesaplarımıza aşağıdan ulaşabilirsiniz!</p><p><a href="https://twitter.com/turkishkit"><strong>Twitter</strong></a><strong> | </strong><a href="https://www.instagram.com/turkish.kit/"><strong>Instagram</strong></a><strong> | </strong><a href="https://www.facebook.com/turkishkit"><strong>Facebook</strong></a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p3cK6QJfCFxsvDBBMcBOLw.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=515751277c4b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/turkishkit/uibutton-configuration-515751277c4b">UIButton Configuration</a> was originally published in <a href="https://medium.com/turkishkit">TalentKit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Emirhan ile göz alıcı iPhone uygulamarı geliştirmenin sırlarını öğrenin.]]></title>
            <link>https://medium.com/turkishkit/emirhan-ile-g%C3%B6z-al%C4%B1c%C4%B1-iphone-uygulamar%C4%B1-geli%C5%9Ftirmenin-s%C4%B1rlar%C4%B1n%C4%B1-%C3%B6%C4%9Frenin-649b4e9d15c2?source=rss----19443271f3c7---4</link>
            <guid isPermaLink="false">https://medium.com/p/649b4e9d15c2</guid>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[course]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Emirhan Erdogan]]></dc:creator>
            <pubDate>Tue, 27 Feb 2024 09:46:06 GMT</pubDate>
            <atom:updated>2024-02-27T09:46:05.877Z</atom:updated>
            <content:encoded><![CDATA[<figure><a href="https://turkishkit.com/?utm_source=medium_newsletter&amp;utm_medium=email"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gL2JmEvmUoDohLTi3iQIvw.png" /></a></figure><p>Her seviyeye uygun birebir dersler ile baştan sona etkileyici bir iPhone uygulaması geliştirmenin tüm inceliklerini öğrenin.</p><p><a href="https://turkishkit.com/?utm_source=medium_newsletter&amp;utm_medium=email"><strong>Detayları Keşfedin</strong></a></p><figure><a href="https://turkishkit.com/?utm_source=medium_newsletter&amp;utm_medium=email"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ADJjZjI-HO2siNtT57QZTA.png" /></a></figure><figure><a href="https://turkishkit.com/?utm_source=medium_newsletter&amp;utm_medium=email"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2F6pmfMxaZSn-gXxii-lxw.png" /></a></figure><blockquote>“Bir iPhone uygulaması geliştirmek, onu hayal etmek ile başlar. Kodlama becerisi, yaratıcı düşünme ve tasarım ile buluşunca ortaya dünyayı değiştirecek ürünler çıkacağına inanıyorum. İşte bu yüzden kodlamayı anlatmakla yetinmiyorum.”</blockquote><figure><a href="https://turkishkit.com/?utm_source=medium_newsletter&amp;utm_medium=email"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zW4dra4hI5MDIfmkFmbUgQ.png" /></a></figure><p><a href="https://turkishkit.com/?utm_source=medium_newsletter&amp;utm_medium=email"><strong>Detayları Keşfedin</strong></a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=649b4e9d15c2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/turkishkit/emirhan-ile-g%C3%B6z-al%C4%B1c%C4%B1-iphone-uygulamar%C4%B1-geli%C5%9Ftirmenin-s%C4%B1rlar%C4%B1n%C4%B1-%C3%B6%C4%9Frenin-649b4e9d15c2">Emirhan ile göz alıcı iPhone uygulamarı geliştirmenin sırlarını öğrenin.</a> was originally published in <a href="https://medium.com/turkishkit">TalentKit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Xcode 15 ile Gelen Yenilikler]]></title>
            <link>https://medium.com/turkishkit/xcode-15-ile-gelen-yenilikler-d6fa6819a0ec?source=rss----19443271f3c7---4</link>
            <guid isPermaLink="false">https://medium.com/p/d6fa6819a0ec</guid>
            <category><![CDATA[xcode15]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[xcode]]></category>
            <dc:creator><![CDATA[Ufuk Köşker]]></dc:creator>
            <pubDate>Fri, 19 Jan 2024 11:04:30 GMT</pubDate>
            <atom:updated>2024-01-19T14:59:08.812Z</atom:updated>
            <content:encoded><![CDATA[<h4>Xcode 15 Güncellemesi: Simülatör runtimes ile tüm platformlara yönelik indirilebilirlik ve diğer yenilikler.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-y3dCHmvVHvfitS_IpL7lA.png" /></figure><p>Merhaba sevgili TurkishKit okuyucuları! 👋🏼 Bugün sizlerle Xcode 15 ile gelen yenilikleri inceleyeceğiz. Hazırsanız hemen başlayalım! 🎊</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6FXzmrIq2tby5Hp8UA6gBA.jpeg" /><figcaption>WWDC23 Demo App</figcaption></figure><p>WWDC23, Apple platform geliştiricileri için heyecan verici bir hafta sunarak, Apple’ın yeni Xcode 15 için bir dizi etkileyici özelliği tanıttığı bir etkinlik oldu. Bu özellikleri başlıkları üzerinden keşfetmeye davet edelim:</p><ul><li><strong>Kod Tamamlama Önceliklendirme:</strong> Xcode 15, çevresel koda dayalı olarak kod tamamlamayı önceliklendirir; bu, değiştiriciler, görünüm özelleştirmeleri ve daha fazlası için en ilgili önerileri sunar.</li><li><strong>Düzenlenmiş Lokalizasyon Varlıkları:</strong> String Catalog’u, lokalizasyon varlıklarını gözden geçirmek ve güncellemek için merkezi ve verimli bir yol sunar, doğruluğu ve tutarlılığı sağlar.</li><li><strong>Geliştirilmiş Belgeleme:</strong> Xcode 15&#39;te güzel bir şekilde tasarlanmış belgeleme arayüzünün tadını çıkarın, gerçek zamanlı önizleme ile öğrenme ve başvuru gezinmesini sorunsuz hale getirir.</li><li><strong>Güçlü Önizlemeler:</strong> Xcode 15&#39;in geliştirilmiş Preview ile arayüzünüzde kolayca iterasyon yapın, anında geri bildirim ve farklı platformlar ile UI çerçeveleri üzerinde özelleştirme seçenekleri sunar.</li><li><strong>Hedefe Özgü #if Önişlemci Makroları:</strong> Xcode 15, mevcut derleme hedefinize dayalı olarak uygulanmayan #if yollarını akıllıca griye çalarak, kod anlama becerilerini artırır ve karmaşıklığı azaltır.</li><li><strong>Git Staging Entegrasyonu:</strong> Git işlemleri artık doğrudan Xcode’a entegre edilmiş durumda, değişiklikleri basit bir tıklama ile aşama alabilir ve kod düzenleyiciden ayrılmadan taahhütlerinizi oluşturabilirsiniz.</li><li><strong>Yeniden Tasarlanmış Test Raporu:</strong> Test raporunun tamamen yeniden tasarlanması, test sonuçlarını daha iyi anlama ve uygun önlemleri alma için yeni araçlar sunar. Ortak hata desenleri de dahil olmak üzere değerli iç görüler elde edin.</li><li><strong>Çarpıcı Hızlı Bağlantı:</strong> 5 kata kadar daha hızlı bağlantı hızını deneyimleyin, derleme sürelerinizi optimize edin ve üretkenliğinizi artırın. Yeni bağlayıcı, hata ayıklama ikili boyutunu %30&#39;a kadar azaltarak disk alanı tasarrufu sağlar ve derleme performansını artırır.</li><li><strong>Bookmark Navigator:</strong> Önemli kod işaretlerini takip edin ve yeni Bookmark Navigator ile görevleri etkili bir şekilde düzenleyin.</li></ul><p>Xcode 15&#39;teki bu heyecan verici yeni özellikler, geliştiricilere iş akışlarını optimize etme, performanslarını artırma ve Apple platformu üzerinde kodlama deneyimlerini geliştirme imkanı tanıyor. Her bir özelliği daha iyi anlamak için örnekler sunalım.</p><h4>Kod Tamamlama Önceliklendirme</h4><p>Xcode 15&#39;te, çevresel koda dayalı olarak en ilgili önerilere öncelik veren geliştirilmiş bir kod tamamlama deneyimi yaşayacaksınız. Bu güncelleme, belirli bir görünüm için uygun değiştiriciyi seçerken veya bir görünümü özelleştirirken değiştiricileri zincirleme kullanırken doğru ve zamanında öneriler almanızı sağlar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3KJtypluIE9oWlJC7LS-Bw.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fdyVl87e_s0k2oInifw8rg.jpeg" /></figure><h4>String Kataloğu</h4><p>Xcode 15, geliştiricilere lokalizasyon varlıklarını gözden geçirme ve güncelleme konusunda merkezi ve verimli bir yol sunan yeni String Kataloğu ile lokalizasyon varlıklarının yönetimini kolaylaştırıyor. String Kataloğu, lokalize edilmiş dizelerinizi kolayca yönetebileceğiniz özel bir merkez olarak hizmet verir. Bu merkezi yaklaşım, lokalize içeriği gözden geçirme ve değiştirme sürecini basitleştirerek farklı diller arasında doğruluk ve tutarlılık sağlamanıza olanak tanır.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qtZjjyu4qXVOgj-sMMri7g.jpeg" /></figure><h4>Asset Catalog için Semboller</h4><p>Xcode artık otomatik olarak Asset Catalog kaynakları için semboller üretir. Bu, bu sembollerin kod tamamlamada görüneceği anlamına gelir, böylece asset içindeki varlıklarınızı kodunuz içinde kullanmak son derece kolay hale gelir. Bu özelliği entegre ederek, tür güvenliğinden faydalanabilir ve varlıklarınızın çalışma zamanında hazır olduğunu bilmenin huzurunu yaşayabilirsiniz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zXTTyuAKuK7fsjdezofqZQ.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZU-I-WuCv5jQ5bwt8hdP1A.jpeg" /></figure><h4>Preview ve Swift Macro’ları</h4><p>Xcode’un önizlemeleri, UI üzerinde hızlı iterasyon yapmayı sağlayarak geliştiricilere anında geri bildirim sunar. Xcode 15 ile gelen geliştirmeler, önizlemeleri daha kullanıcı dostu hale getirir ve Swift Makroları’nı içeren yeni bir sözdizimi tanıtır. Farklı platformlar ve cihazlarla çalışma kolaylığı artar, istenen platformları ve cihazları kolayca seçebilirsiniz. Önemli bir yenilik ise Previews’ın artık tüm UI çerçevelerinde kullanılabilir olmasıdır. SwiftUI, UIKit veya AppKit kullanın, kodunuzun konumuna bakılmaksızın tutarlı bir deneyimle UI üzerinde sorunsuz iterasyon yapabilirsiniz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ekmpZHfmFDJwI6M3UaHE8g.jpeg" /></figure><h4>Seçilen Derleme Hedefi İçin Önişlemci Makroları</h4><p>Xcode 15, derleme hedefinize uygulanmayan #if yollarını otomatik olarak griye boyama özelliği ile geliyor. Bu, hedef platforma özgü olmayan kodları görsel olarak belirginleştirerek, geliştiricilere etkin ve uygulanabilir kod yollarına odaklanma imkanı sağlıyor. Bu özellik, kod anlama sürecini hızlandırır ve karışıklıklardan kaçınmanıza yardımcı olur. Xcode 15&#39;in bu geliştirmesi, koşullu derleme direktifleriyle çalışmayı basitleştirir, böylece hangi kod bölümlerinin dahil edileceğini veya hariç tutulacağını hızla anlamanıza olanak tanır. Bu, kod okunabilirliğini artırır ve geliştirme sürecinizi daha verimli hale getirir.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U82n4rzToKucrIUMILaHGw.jpeg" /></figure><h4>Git Staging Entegrasyonu</h4><p>Xcode, değişiklikleri git aşama işlemiyle arayüzde entegre ederek taahhüt sürecini sadeleştirir. Bir tıklama ile değişiklikleri geri alma veya çıkarma kolaylığı sağlar. Source Control gezgini, değişiklikleri kapsamlı bir şekilde gözden geçirme ve stage sürecini verimli hale getirir. Bu entegrasyon, kod yönetimini basitleştirir.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2WILLd7NyfSL48OUPlafJg.jpeg" /></figure><h4>Yeniden Tasarlanmış Test Raporu</h4><p>Xcode 15, test raporunu kapsamlı bir şekilde yeniden tasarlayarak, hata desenlerini vurgulayan değerli Üst İncelemeler ve daha yapılandırılmış bilgilerle test sonuçlarınızı anlamanıza olanak tanır. Bu yeni tasarım, test iş akışınızı iyileştirir ve sorunları belirleme ve ele alma sürecini basitleştirir, böylece güvenle sağlam ve güvenilir bir uygulama geliştirebilirsiniz.</p><h4>Lightning-Fast Linking</h4><p>Xcode, uygulamalarınızı daha hızlı build etmenizi sağlayacak iki önemli güncelleme aldı! Bunlardan birincisi tamamen yenilenen bağlayıcı(linker) sayesinde bağlantı hızının 5 kat artması. Bu, proje kaydettikten sonra bekleme süresini ciddi şekilde kısaltarak geliştirme hızımızı arttırıyor. İkincisi ise hata ayıklama için kullanılan test sürümlerinin boyutunu %30&#39;a kadar küçültmek. Böylece hem diskten yer tasarrufu sağlanıyor hem de daha hızlı hata ayıklama imkanı sunuluyor. Bu yenilikler sayesinde kodlamaya daha fazla zaman ayırabilir, bekleme süresinden kurtulabilirsiniz.</p><h4>Bookmark Navigator</h4><p>Xcode’un Bookmark Navigator, kodunuzdaki önemli noktaları takip etmenizi ve görevlerinizi düzenlemenizi sağlayan yeni bir özelliktir. Kodunuzdaki kritik bölümleri veya belirli satırları kolayca işaretleyebilir, bu işaretlerle hızlıca gezinebilirsiniz. Yer işaretleri, kod tabanınızdaki önemli noktaları pratik bir şekilde işaretleme ve bulma imkanı sunar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TrUYaosiX6HKagHUS-Ix2w.jpeg" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/950/1*i6DOG1Dbi4JxiuqB_BjPAQ.jpeg" /></figure><p>Bir makalemizin daha sonuna gelmiş bulunuyoruz. Bu yazımızda <strong>Xcode 15</strong> ile gelen yenilikleri ele aldık. İlerleyen zamanlarda paylaşacağımız yeni makalelerde görüşmek üzere, hoşça kalın! 👋</p><p>Bizi daha yakından takip etmek istiyorsanız, sosyal medya hesaplarımıza aşağıdan ulaşabilirsiniz!</p><p><a href="https://twitter.com/turkishkit"><strong>Twitter</strong></a><strong> | </strong><a href="https://www.instagram.com/turkish.kit/"><strong>Instagram</strong></a><strong> | </strong><a href="https://www.facebook.com/turkishkit"><strong>Facebook</strong></a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*k_QS5AsRfybNINGZSpoZQw.png" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d6fa6819a0ec" width="1" height="1" alt=""><hr><p><a href="https://medium.com/turkishkit/xcode-15-ile-gelen-yenilikler-d6fa6819a0ec">Xcode 15 ile Gelen Yenilikler</a> was originally published in <a href="https://medium.com/turkishkit">TalentKit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Scholarship Projesi: Püf Noktaları ve Sık Yapılan Hatalar]]></title>
            <link>https://medium.com/turkishkit/scholarship-projesi-p%C3%BCf-noktalar%C4%B1-ve-s%C4%B1k-yap%C4%B1lan-hatalar-725b4fb4dfdc?source=rss----19443271f3c7---4</link>
            <guid isPermaLink="false">https://medium.com/p/725b4fb4dfdc</guid>
            <category><![CDATA[swift-student-challenge]]></category>
            <category><![CDATA[swift-playgrounds]]></category>
            <category><![CDATA[turkishkit]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[app-development]]></category>
            <dc:creator><![CDATA[M. Bertan Tarakçıoğlu]]></dc:creator>
            <pubDate>Mon, 14 Mar 2022 14:03:32 GMT</pubDate>
            <atom:updated>2022-04-17T10:33:35.501Z</atom:updated>
            <content:encoded><![CDATA[<h4>Playground projesi hazırlarken karşılaşılan spesifik sorunların üstesinden nasıl gelebileceğinizi öğrenin!</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*l917W_UUnBGYEdjxdVzQxQ.png" /></figure><blockquote><strong>Not:</strong> An itibarıyla WWDC22 Swift Student Challenge kuralları açıklandı ve <strong>bu yılki proje formatı Playground App, ve bu makalede bahsettiğimiz Playground Book değil!</strong></blockquote><blockquote><a href="https://developer.apple.com/wwdc/swift-student-challenge/">Daha fazla bilgi için Swift Student Challenge web sitesini ziyaret edin.</a></blockquote><p>Merhaba sevgili TurkishKit okurları! WWDC ile birlikte Swift Student Challenge her geçen gün yaklaşıyor! Bu yüzden bu makalemizde sizlere Playground projelerinizi kodlarken sıkça karşılaşabileceğiniz ve bazen sinir bozucu olabilen hatalardan, onları nasıl çözebileceğinizden ve püf noktalarından bahsedeceğiz.</p><h3>Playgrounds ve SwiftUI</h3><p>Apple’ın 2019’da çıkardığı ve bizim TurkishKit’te kullanmayı çok sevdiğimiz SwiftUI teknolojisini Playground projelerinizde de aşağıdaki gibi basitçe kullanabilirsiniz.</p><pre><strong>import </strong>PlaygroundSupport<br><strong>import</strong> SwiftUI</pre><pre><em>// Standard bir SwiftUI görünümü olan ContentView</em><br><strong>struct</strong> ContentView: View {<br>    <strong>var</strong> body: <strong>some</strong> View {<br>        Text(“Hello, TurkishKit”)<br>            .font(.largeTitle)<br>    }<br>}</pre><pre><em>// Live View’a ContentView görünümünü atıyoruz</em><br>PlaygroundPage.current.setLiveView(ContentView())</pre><p>İlk olarak kaynak kodumuzun en başında PlaygroundSupport teknolojisini ekliyoruz — bu şekilde Playgrounds uygulaması oluşturabilmek için gerekli kaynak kodlara erişiyoruz.</p><p>Ardından kodumuzun son satırındaki .setLiveView komutu ile Playgrounds uygulamasının sağ kısmındaki içerikleri görüntülemekle sorumlu bölüm olan <em>Live View’a </em>ContentView objesinin görüntülemesini söylüyoruz.</p><p>Bu komuta PlaygroundLiveViewable protokolüne uyan her objeyi atayabilirsiniz, yani sadece SwiftUI View objeleri ile sınırlı değilsiniz! 😄</p><h3>Playgrounds ve UIKit</h3><p>PlaygroundLiveViewable protokolüne uydukları için UIView ve UIViewController objelerini de bir önceki adımda kullandığımız iki komutu kullanarak <em>LiveView’da</em> görüntüleyebilirsiniz.</p><p>Aşağıdaki örnekte standard bir UIView objesinin <em>LiveView’a</em> nasıl atandığını görmektesiniz.</p><pre><strong>import</strong> PlaygroundSupport<br><strong>import</strong> UIKit</pre><pre><strong>var</strong> view = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 50))</pre><pre><strong>var</strong> label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 50))</pre><pre>label.text = &quot;Hello, TurkishKit&quot;<br>label.font = .preferredFont(forTextStyle: .largeTitle)</pre><pre>view.addSubview(label)</pre><pre>// view görünümünü LiveView&#39;a atıyoruz<br>PlaygroundPage.current.setLiveView(view)</pre><p>Şimdiyse de bir UIViewController objesini görmektesiniz. Temel mantık gördüğünüz gibi hiç değişmiyor.</p><pre><strong>import</strong> PlaygroundSupport<br><strong>import</strong> UIKit</pre><pre><strong>class</strong> ViewController: UIViewController {<br>    <strong>var</strong> label: UILabel!<br>  <br>    <strong>override</strong> <strong>func</strong> viewDidLoad() {<br>        <strong>super</strong>.viewDidLoad()<br>        label = UILabel(frame: CGRect(x: 0, y: 0, width: 300, height: 50))<br>        <br>        label.text = “Hello, TurkishKit”<br>        label.font = .preferredFont(forTextStyle: .largeTitle)</pre><pre><strong>        self</strong>.view.addSubview(label)<br>    }<br>}</pre><pre><br>PlaygroundPage.current.setLiveView(ViewController())</pre><h3>Live View’u Tam Ekran Haline Getirme</h3><p>Normal şartlar altında <em>Live View</em> görünümü cihaz ekranın sadece yarısını kaplıyor, ancak zaman zaman bütün ekranın kaplanmasını istediğiniz durumlar olabilir. Bunun için kodunuzun sonuna aşağıdaki komutu eklemeniz yeterli.</p><pre>PlaygroundPage.current.wantsFullScreenLiveView = <strong>true</strong></pre><blockquote><strong>Not:</strong> Playgrounds uygulamasındaki bir hatadan dolayı komutu ilk eklediğinizde biraz tutukluk yapabiliyor. Uygulamayı yeniden başlattığınızda olması gerektiği gibi çalışacaktır.</blockquote><h4>Image Sorunu</h4><p>Daha önceki bir makalemizde uygulamalarınızda Image görünümünü ile nasıl görsel ekleyebileceğinizi keşfetmiştik. Makalemize aşağıdan ulaşabilirsiniz:</p><p><a href="https://medium.com/turkishkit/swiftui-image-e6fdc2c67f81">SwiftUI: Image</a></p><p>Ancak Swift Playgrounds’a gelince işler biraz değişiyor, çünkü Image görünümünü aşağıdaki gibi kullanmaya çalıştığınızda sadece boş bir görüntü ile karşılaşıyorsunuz.</p><pre>Image(“Photo”)<br>    .resizable()<br>    .scaledToFit()<br>    .frame(width: 400)</pre><p>Bunu Image görünümüne UIImage tipinde bir değer atayarak çözebiliyoruz, ancak her seferinde bunu yapmak kodunuzu uzatacak ve okunurluğunu azaltacaktır.</p><p>Bunun yerine UIImage görünümünü aşağıdaki extension ile genişleterek, Image görünümünün bundan sonra kendisine atanan String değerlerini önce bir UIImage değerine çevirip sonra onu kullanmasını sağlamak çok daha temiz bir çözüm.</p><pre><strong>extension</strong> Image {<br>  init(_ named: String) {<br>    <strong>self</strong>.init(<br>      uiImage: UIImage(<br>        imageLiteralResourceName: named<br>      )<br>    )<br>  }<br>}</pre><p>İşte bu kadar! Artık Image görünümlerini Playgrounds üzerinde her zaman olduğu gibi kullanmaya devam edebilirsiniz.</p><blockquote><strong>Not:</strong> Sağladığınız isimde bir görselin proje dosyalarında olduğuna dikkat edin. Standard bir SwiftUI projesinde görsel bulunmadığı takdirde sadece boş bir görüntü oluşmakta, ancak bu yöntemde Playground kodunuz tamamen çöküyor.</blockquote><h3>Playground Sonuçlarını Etkisizleştirmek</h3><p>Buraya kadar hatasız bir proje ortaya çıkartmamıza rağmen, kaynak kodunuz arttıkça bir noktadan sonra pek anlam veremediğiniz bir <em>runtime error</em>, yani çalıştırma hatası alabilirsiniz.</p><p>Bu oldukça sinir bozucu, ancak çözmesi de bir o kadar kolay olan bir sorundan kaynaklanıyor: <em>Sonuçları Etkinleştir (Enable Results)</em> özelliğinin açık olması.</p><p>Özelliği kapatmak için aşağıdaki gibi <em>Kodumu Çalıştır</em> botunun yanındaki hız göstergesine benzer butona dokunup, açılan menüden Sonuçları Etkinleştir seçeneğini kapatın. Apple’ın aşağısına düştüğü nottaki gibi özellik performansı azalttığından dolayı bu soruna sebebiyet veriyor.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KCayrPOHK5gOS9ZK6v8ocw.gif" /></figure><p>Projeniz artık sorunsuz bir biçimde çalışmalı. Ancak problem hâlâ tamamen çözülmüş diyemeyiz, çünkü projenizi bir dahaki açışınızda <em>Sonuşları Etkinleştir </em>özelliği kendiliğinden tekrar aktifleştirilecek. Bir sonraki adımda bunu nasıl engelleyebileceğimizi keşfediyoruz.</p><h3>Manifesto!</h3><p>Her Swift Playground kitabı (Playground Book) ayarlarını ve özelliklerini belirleyen manifest.plist isminde bir dosyaya sahip. Buna ek olarak Playground kitabınızın bölümü ve her sayfası için de yine aynı isim ve uzantıya sahip bir dosya bulunmakta.</p><blockquote><strong>💡İpucu:</strong> Eğer daha önce karşılaşmadıysanız, plist dosyaları Apple geliştirici ekosisteminde sıklıkla kullanılan; özellik, bilgi ve ayarların depolandığı dosyalardır.</blockquote><p>İlk olarak sayfa ayarlarını belirleyen Manifest.plist dosyasını inceleyelim. Bunun için Xcode yüklü bir Mac bilgisayarına ihtiyacınız olacak.</p><p>İlk olarak Playground projenizi Finder’da bulun. Ardından projenize sağ tıklayarak aşağıdaki gibi <em>Paket İçeriğini Göster’i </em>tıklayın — sizi projenizin kaynak dosyaları bekliyor olacak. 😎</p><p>Sonrasında aşağıda gördüğünüz gibi bu uzun dosya adresini takip edip sayfa ayarlarını belirleyen Manifest.plist dosyasını Xcode ile açın.</p><p><em>Dosya konumu: /Chapters/</em><strong><em>Chapter1</em></strong><em>.playgroundchapter/Pages/</em><strong><em>My Playground</em></strong><em>.playgroundpage/Manifest.plist</em></p><p>Kalın font ile yazılı kısımlar düzenlediğiniz Playground ve sayfaya göre değişiklik gösterebilir.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ViptfeeJJ_VP7mkAODq-lw.gif" /></figure><p>Aşağıdaki gibi açılan editördeki anahtar değerlerinin üzerindeki artı sembolüne tıklayarak yeni bir anahtar ekleyin. Anahtar ismi PlaygroundLoggingMode, ve değeri de Off olmalı. Ayrıca anahtar veri tipinin bir <strong>String</strong> olmasına dikkat edin.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9U1-Hjkmj4nH6BjmKfaiBw.gif" /></figure><p>🥳 İşte bu kadar! Artık <em>Sonuçları Etkinleştir </em>tamamen devre dışı kalmakla birlikte Playgrounds uygulamasında gözükmeyecek bile.</p><blockquote><strong>Not:</strong> Projeniz birkaç sayfadan oluşuyorsa sonu .playgroundpage uzantısıyla biten bütün klasörlerin içerisindeki Manifest.plist dosyaları için bu adımı tekrarlamanız gerekmekte.</blockquote><p><strong>👀 Eğer bir Mac bilgisayarına sahip değilseniz bu sizin için! </strong><em>Sonuçları Etkinleşti</em>r ayarı yukarıdaki adımlar ile tamamen kaldırılmış bir Playground proje şablonu oluşturduk. Aşağıya tıklayarak GitHub’dan indirebilirsiniz.</p><p><a href="https://github.com/TurkishKit/TukishKit-Playgrounds-Template.git">GitHub - TurkishKit/TukishKit-Playgrounds-Template: Sonuçları etkinleştir özelliği kapatılmış, SwiftUI tabanlı Playground kitabı şablonu!</a></p><p>Manifest.plist dosyasını kaptmadan önce bir seçeneğe daha değinelim. En üst kısımda gördüğünüz anahtar LiveViewEdgeToEdge, isminden de anlayabileceğimiz üzere Live View görünümünün pencere boyunca genişletilmesini sağlıyor.</p><p>Anahtar <strong>Bool</strong> tipinde ve şu anda 0 (false). Etkinleştirmek için bu değeri 1 (true) olarak değiştirin ve kaydedin.</p><p>Lütfen etkinleştirmeden önce bu ayarın <em>Kodumu Çalıştır </em>ve yanında bulunan iki butonun da proje görünümüzün içine alınmasına neden olacağını göz önünde bulundurun — çoğunlukla oyun ve kamerayı kullanan projeler için uygun.</p><p>Bu bölümde olası anahtarlardan sadece iki tanesine göz attık, ama seçenekler sadece bunlarla sınırlı değil! Eğer merak ediyorsanız aşağıdaki sayfada anahtarların tam bir listesi mevcut. 😌</p><p><a href="https://developer.apple.com/documentation/swift_playgrounds/structuring_content_for_swift_playgrounds/adding_a_page_to_a_playground_book">Apple Developer Documentation</a></p><h3>Kapak Resmi Eklemek</h3><p>Projenize bir kapak resmi ekleyerek bir kimlik kazanmasını sağlayabilir ve onu öne çıkarabilirsiniz! Şimdi ressam şapkanızı takın çünkü yapmanız gereken ilk şey kapak tasarımınızı yapmak olacak. 🧑‍🎨</p><blockquote><strong>Not:</strong> Kapak resminiz .png formatında ve 400 x 300 piksel boyutlarında olmalı.</blockquote><p>Tasarım işi bittikten sonra kapağı Playground projenize eklemeye geçebiliriz.</p><p>Şimdi yine <em>Paket İçeriğini Göster </em>seçeneğini kullanarak proje kaynak dosyalarını görüntüleyin. Ardından <em>Contents</em> klasörünü açıp içinde hali hazırda yoksa <em>PrivateResources</em> isminde bir klasör oluşturun. Şimdi bu klasörü açın ve yukarıdaki özelliklere uyduğundan emin olduğunuz kapak resminizi içine taşıyın. Sonra da ismini cover.png olarak değiştirin.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6FoSK8SNK-AIZfy97ETP4Q.gif" /></figure><p>Harika! Şimdi yapmamız gereken sadece tek bir şey kaldı: Playgrounds uygulamasını kapak resminizin nerede olduğunu söylemek. Finder’ın geri gitme butonunu kullanarak Contents klasörüne geri gidin ve karşınıza çıkan Manifest.plist Xcode ile açın. Bu dosya genel kitap ayarlarının düzenliyor.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HIXyMeOsUwkpIYHdsQBURQ.gif" /></figure><p>Şimdiyse de yine herhangi bir anahtarın yanındaki artı sembolüne tıklayarak listeye yeni bir anahtar ekleyin: ImageReference. Değeri ise kapak resminizin dosya ismi olmalı, yani String veri tipinde cover.png.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LPav201RZBKyRIZsjzjC_w.gif" /></figure><p>Tebrikler! 🥳 Kapak resminiz artık hazır. Eğer kapak resminiz Playgrounds uygulamasıda hemen görünmezse projenizin bir kopyasını oluşturup içe aktarmayı ya da az sonra nasıl yapılacağını keşfedeceğimiz <em>Yeni Oyun Alanı Olarak Dışarı Aktar</em> özelliğini denemenizi öneririm.</p><p>Ayrıca aşağıdaki sayfadan da Playground proje ayarlarını belirleyen Manifest.plist dosyasına ekleyebileceğiniz anahtarların tam bir listesine ulaşabilirsiniz.</p><p><a href="https://developer.apple.com/documentation/swift_playgrounds/structuring_content_for_swift_playgrounds">Apple Developer Documentation</a></p><h4>Cihaz Yönü</h4><p>Playground projelerinizde birçok farklı nedenden dolayı cihaz yönüne (device orientation) ihtiyaç duyabilirsiniz. Maalesef Playgrounds uygulamasında cihaz yönüne erişmek sıkıntılı bir sürece dönüşebiliyor.</p><p>UIDevice.current.orientation özelliği ile cihaz yönüne kolayca erişebiliyorsunuz.</p><p>Maalesef ki kodunuz Playgrounds ortamında çalışıyorsa bu komut yanlış çalışıyor.</p><p>Eğer projeniz UIKit tabanlıysa, ideal olmamasına rağmen cihaz yönüne UIViewController tipine ait ve iOS 8&#39;de <em>deprecate edilmiş </em>(kullanımdan kaldırılmış) interfaceOrientation değişkeni ile erişebilirsiniz.</p><p>Eğer projeniz UIKit tabanlıysa, ideal olmamasına rağmen cihaz yönüne UIViewController tipine ait ve iOS 8&#39;de <em>deprecate edilmiş </em>(kullanımdan kaldırılmış) interfaceOrientation değişkeni ile erişebilirsiniz.</p><blockquote><strong>Not:</strong><em> Deprecate edilmesi,</em> Apple’ın bu komutu kullanımdan kaldırması, ancak hali hazırda bu komutu kullanan uygulamalarda sorun oluşmaması için kaynak kodunda uyarıya sebep olmasına rağmen kullanımına izin verdiği anlamına geliyor.</blockquote><p>Ekleyelim ki bu sadece geçici bir çözüm ve siz bunu okurken kullanımdan tamamen kaldırılmış bile olabilir! 🤯</p><p>Çoğu zaman yerlerini yenileri (ve daha iyileri) aldığı için komutlar <em>deprecate edilir</em>. <strong>Normal Şartlar altında bu komutlardan uzak durmalısınız.</strong></p><h4>PlaygroundKeyValueStore</h4><p>PlaygroundKeyValueStore, temelde UserDefaults ile aynı görev ve amaca sahip, ancak isminden de anlaşılacağı üzere Playground projeleri için çok daha uygun. Daha önce UserDefaults ile çalışmadıysanız, bu makalemize bir göz atabilirsiniz:</p><p><a href="https://medium.com/turkishkit/swift-ile-veri-kaydetme-userdefaults-e62dc46f5802">UserDefaults</a></p><p>PlaygroundKeyValueStore kaydettiği değerleri .playgroundbook dosyasının içinde depoluyor. Eğer playground dosyasını iCloud’da depoluyorsanız, PlaygroundKeyValueStore siz hiçbir şey yapmadan kaydettiğiniz verileri iCloud üzerinden senkronize ediyor. Bu, proje dosyanızı paylaştığınız durumda kaydedilen verilerin de paylaşılması demek, o yüzden kişisel veriler konusunda dikkatli olun!</p><p>Vari kaydetmeyle işe başlayalım. Aşağıdaki örnekte bir <strong>String</strong> değeri olan kullanıcı adını username isimli anahtara kaydediyoruz:</p><pre>PlaygroundKeyValueStore.current[“username”] = .string(“Craig”)</pre><p>Yukarı da da gördüğünüz üzere kaydedilen veri tipini bir <strong>enum</strong> değeri ile belirliyoruz. Bunun nedeni PlaygroundKeyValueStore mekanizmasının sadece belli başlı verileri kabul eden PlaygroundValue veri tipini depolayabilmesi.</p><p><strong>Aşağıda </strong><strong>PlaygroundValue tarafından desteklenen bütün veri tipleri için basit örnekler yer almakta:</strong></p><ul><li>.boolean(true)</li><li>.data(Data(&quot;Tim&quot;.utf8))</li><li>.date(Date())</li><li>.floatingPoint(42.53)</li><li>.integer(42)</li><li>.string(&quot;Steve&quot;)</li><li>.none (Tutulan veriyi temizler ve <strong>nil</strong> değerini atar.)</li></ul><p>Ayrıca sadece yukarıdaki PlaygroundValue tipindeki değerler içeren Array değerlerine ek olarak anahtarları <strong>String</strong> ve değerleri PlaygroundValue tipindeki değerleri depolayabiliyorsunuz. Örnekler aşağıda:</p><ul><li>.array(.integer(4), .integer(2))</li><li>.dictionary([&quot;appleWeight&quot;: .floatingPoint(42.53), &quot;strawberryWeight&quot;: .floatingPoint(12.34)])</li></ul><p>Şimdiyse kaydedilen değerlere nasıl erişeceğimize göz atalım. Bu kısım olduğu şey için biraz karışık gelebilir, merak etmeyin, hepsinin üstünden tek tek geçeceğiz. Aşağıdaki örnekte kaydettiğimiz kullanıcı adına erişiyor ve konsola yazdırıyoruz.</p><pre>// Anahtar için bir değer olduğunu doğrula<br><strong>if</strong> <strong>let</strong> keyValue = PlaygroundKeyValueStore.current[&quot;username&quot;] {<br>    // Değerin String veri tipinde olduğunu doğrula<br>    <strong>if</strong> <strong>case</strong> .string(<strong>let</strong> name) = keyValue {<br>        // Değeri yazdır<br>        print(&quot;Merhaba, \(name)!&quot;)<br>    } <strong>else</strong> {<br>        print(&quot;Değer yanlış veri tipinde&quot;)<br>    }<br>} <strong>else</strong> {<br>    print(&quot;Değer bulunamadı&quot;)<br>}</pre><p>İlk önce bir <strong>if let</strong> ifadesiyle anahtarımıza ilişik kayıtlı veri olduğunu doğruluyoruz ve bulunan veriyi keyValue ismindeki bir sabite atıyoruz. Bulunamadığı halde konsola bir hata mesajı yazdırıyoruz.</p><p>Ancak elimizdeki verinin hangi veri tipinde olduğunu hâlâ bilmiyoruz. Burada kullandığınız veri tipi, değeri kaydederken kullandığınız veri tipinin aynısı olmalı.</p><p>Sonraki adımda <strong>if case</strong> ifadesiyle önceden oluşturduğumuz keyValue sabitinin .string tipinde olduğundan emin olup, onu name isminde başka bir sabite atıyoruz. Aksi takdirde yine konsola hata mesajı yazdırıyoruz.</p><p>Her şey yolunda gittiyse artık name değişkeni üzerinden kaydettiğimiz değere erişebilirsiniz.</p><h4>Playground Modüllerini Kullanın</h4><p>Düzenli ve okunması kolay bir projeye sahip olmak için farklı amaçlara hizmet eden kod parçacıklarını kendi modüllerine ayırmak her zaman iyi bir pratik olarak kabul edilir.</p><p>Ancak Swift Playgrounds üzerinde bir birinden ayrı Swift dosyaları oluşturmak için en az bir tane modüle ihtiyacımız var. Swift Playgrounds’taki bu modülleri Xcode’taki <a href="https://developer.apple.com/documentation/swift_packages">Swift Package Manager</a>’a (SPM) benzetebiliriz.</p><p>Hadi gelin biz kendi modülümüzü oluşturalım. Aşağıdaki gibi proje dosyaları menüsünün <em>Kaynak Kodu </em>yazan kısmının hemen sağında bulunan artı butonuna tıklayarak yeni bir modül oluşturun ve TurkishKit olarak adlandırın.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MbSQmHZtsbasuW13LhvECQ.gif" /></figure><p>Modüller içerisinde birden fazla Swift dosyası barındırabiliyor, bu yüzden proje yapınızı oluştururken modülleri Xcode’daki grup klasörleri gibi düşünebilirsiniz. İhtiyacınız oldukça aşağıdaki gibi modül isminizin sağındaki artı sembolünü kullanarak Swift dosyaları ekleyebilirsiniz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sfU3kDVnbbi5FH1JbTYTKA.gif" /></figure><p>Playground modüllerinde dikkat etmeniz gereken iki ek nokta bulunmakta. Bunlardan ilki <em>Access Control</em>.</p><p>Modüllerinizin içerdiği <strong>class</strong>, <strong>struct</strong> ve <strong>enum</strong> benzeri yapılara, içerdikleri değişkenlere ve metotlara diğer modüller ve sayfalardan erişebilmeniz için <strong>public</strong> anahtar kelimesiyle işaretlemeniz gerekmekte.</p><p>Normal şartlar altında bir Xcode projesinde oluşturduğunuz Swift dosyalarının içeriklerine erişmek için <strong>public</strong> ile işaretlemeye ihtiyaç duymazsınız. Ancak Playgrounds kullanırken sadece dosya değil, dosyaları içeren modüller oluşturuyoruz, ve modüller <strong>public</strong> işaretini zorunlu kılıyor.</p><p>Eğer <em>Access Control</em> ile ilk kez çalışıyorsanız onunla ilgili bir yazımız da mevcut. 😄</p><p><a href="https://medium.com/turkishkit/swift-access-control-af81ee7ddbbf">Swift: Access Control</a></p><p>İkinci nokta da <strong>import</strong> komutları. Playgrounds uygulaması oluşturduğunuz modülleri Playground sayfalarına otomatik olarak dahil etmekte, ancak bir modülü başka bir modül içerisinde kullanmak istediğinizde bir <strong>import</strong> komutuna ihtiyacınız var. Diyelim ki oluşturduğumuz TurkishKit modülünün içinden bir <strong>class</strong> yapısına Playgrounds uygulamasının otomatik oluşturduğu UserModule modülünün SharedCode.swift dosyasından erişmek istiyorsunuz. Aşağıdaki gibi bir <strong>import</strong> komutu yardımıyla TurkishKit modülünü dosyaya dahil etmelisiniz.</p><pre>// UserModule/SharedCode.swift:</pre><pre><strong>import</strong> TurkishKit</pre><h4>Yeni Playground Olarak Dışa Aktar</h4><p>Eğer bir Mac bilgisayarına sahipseniz, Playgrounds uygulamasının <em>Yeni Playground Olarak Dışarı Aktar </em>özelliğinden yararlanarak özel alt başlık ve sıfırlama noktasına sahip bir Playground kitabı dosyası oluşturabilirsiniz.</p><p>Sıfırlama noktası, sizin ya da diğer kullanıcıların yaptığı değişikleri kolayca silmenize ve kaynak kodunuzu orijinal haline getirmenizi sağlıyor. Oldukça havalı. 😎</p><p>Yapmanız gereken ilk şey projenizi açmak olacak. Ardından menü çubuğunun dosya menüsünde bulunan <em>Yeni Playground Olarak Dışarı Aktar</em> seçeneğine tıklayın. Açılan pencerede değerleri istediğiniz gibi kişiselleştirebilirsiniz. Content ID bölümünü olduğu gibi bırakıp geçebilirsiniz, ancak sıfırlama noktası oluşturmak için alttaki seçeneğin işaretli olduğundan emin olun!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NP-FNgtrZNdodUmzqghuGg.gif" /></figure><p>İşlem tamamlandığında Playground projeniz iCloud Playgrounds klasörüne aktarılmış olacak.</p><h3>Son Birkaç İpucu! 👀</h3><p>Makaleyi sonlandırmadan önce Scholarship Projesi hazırlama sürecinde işinize yarayacak birkaç ipucu paylaşmak istiyorum.</p><h4><strong>Xcode Projesinde Kodlayın, Sonra Playgrounds’a Aktarın</strong></h4><p>Projenizi ya Playgrounds uygulamasında ya da Xcode kullanarak <a href="https://medium.com/turkishkit/playground-swift-playgrounds-author-template-6e80f4c565b8"><em>Playgrounds Author Template</em></a> ile yapıyor olun, standard bir Xcode projesinde çalışmak size çok daha iyi bir deneyim sunacak ve zaman kazanmanızı sağlayacaktır.</p><p>Mesela Swift Playgrounds’da CMD + F kısayoluyla arama özelliği bulunmuyor ve <a href="https://medium.com/turkishkit/playground-swift-playgrounds-author-template-6e80f4c565b8"><em>Author Template</em></a>’ı kullanırken de kod tahmini özelliği devre dışı kalıyor.</p><h4><strong>Playgrounds Hatalarına Hazırlıklı Olun!</strong></h4><p>Bu makalede de gördüğünüz üzere Swift Playgrounds uygulamasında her şey beklediğiniz gibi çalışmayabilir. Bu yüzden kodunuzu bir Xcode projesinden Playgrounds’a aktardıktan sonra meydana gelebilecek hataları göz ününde bulundurun ve proje sürecinizi planlarken bu hatalarıda çözmeye de zaman ayırın. <strong>Aksi takdirde son anda beklenmedik bir hatadan dolayı projeniz başarısız olabilir.</strong></p><h4>Playground Kitabı Formatından Yararlanın</h4><p>Projenizin benim şimdiye kadar yaptıklarım gibi Playgrounds ortamında çalışan bir uygulama gibi olabileceği gibi, <em>Playground Book </em>formatından da yararlanabileceğini unutmayın.</p><p><em>Playgrounds Author Template </em>kullanarak kullanıcıya herhangi bir konsepti adım adım ve interaktif bir şekilde adeta bir kitap gibi öğreten bir Playground projesi oluşturabilirsiniz.</p><p>Playground Book ve Author Template ile ilgili yazımızı da aşağıya bırakıyorum. Okumanızı mutlaka öneririm. 😄</p><p><a href="https://medium.com/turkishkit/playground-swift-playgrounds-author-template-6e80f4c565b8">Playground: Swift Playgrounds Author Template</a></p><p>Böylece bir yazımızın daha sonuna gelmiş oluyoruz. Umuyoruz ki burada öğrendikleriniz sizin için faydalı olur. Eğer bu yıl yarışmaya katılmak istiyorsanız şu an başlamak için harika bir zaman! Bir sonraki yazıya kadar kendinize çok iyi bakın. 😌 İyi şanslar! 🙌</p><p>Bizi daha yakından takip etmek istiyorsanız, sosyal medya hesaplarımıza aşağıdan ulaşabilirsiniz!</p><p><a href="https://twitter.com/turkishkit"><strong>Twitter</strong></a><strong> | </strong><a href="https://www.instagram.com/turkish.kit/"><strong>Instagram</strong></a><strong> | </strong><a href="https://www.facebook.com/turkishkit"><strong>Facebook</strong></a></p><figure><a href="https://medium.com/turkishkit/scholarship-projesi/home"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3rgA__bygk9I0UpXZwPd1Q.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=725b4fb4dfdc" width="1" height="1" alt=""><hr><p><a href="https://medium.com/turkishkit/scholarship-projesi-p%C3%BCf-noktalar%C4%B1-ve-s%C4%B1k-yap%C4%B1lan-hatalar-725b4fb4dfdc">Scholarship Projesi: Püf Noktaları ve Sık Yapılan Hatalar</a> was originally published in <a href="https://medium.com/turkishkit">TalentKit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SwiftUI: PencilKit ile Çizim]]></title>
            <link>https://medium.com/turkishkit/swiftui-pencilkit-ile-%C3%A7izim-e7634014b39a?source=rss----19443271f3c7---4</link>
            <guid isPermaLink="false">https://medium.com/p/e7634014b39a</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[turkishkit]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[M. Bertan Tarakçıoğlu]]></dc:creator>
            <pubDate>Mon, 10 Jan 2022 14:03:09 GMT</pubDate>
            <atom:updated>2023-02-15T10:55:26.592Z</atom:updated>
            <content:encoded><![CDATA[<h4>Kendi çizim uygulamanızı geliştirin!</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gzSUTFvC4qYh0ascoVhqqQ.png" /></figure><p>👋 Hepinize merhaba sevgili TurkishKit okurları! Uzun bir aradan sonra yine heyecan verici bir proje ile sizinleyiz.</p><p>Bu yazımızda birlikte SwiftUI ve PencilKit kullanarak Apple Pencil’ın bütün özelliklerinden yararlanabileceğiniz bir çizim uygulaması geliştireceğiz. Fakat merak etmeyin, bir Apple Pencil’a sahip değilseniz bile bu uygulamayı geliştirebilir ve kullanabilirsiniz. Üstelik hem iPhone ve iPad destekliyor! 😌</p><h3>🚀 Giriş</h3><p>İşe her zaman olduğu gibi yeni bir proje oluşturmakla başlıyoruz. Uygulamanızı Mac bilgisayarınızdaki Xcode uygulamasını kullanarak geliştirebileceğiniz gibi, ben iPad ile yeni çıkan <a href="https://developer.apple.com/swift-playgrounds/">Swift Playgrounds 4</a> sürümünü kullanmak istiyorum. İlk kez WWDC21 konferansında duyurulan bu yeni sürüm, iPad’inizi kullanarak uygulama geliştirmenize ve App Store’da yayınlamanıza olanak veriyor. Oldukça heyecanlı!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/871/1*X_nb6DeuGS2Dbwm8V9bHpA@2x.jpeg" /><figcaption>Swift Playgrounds 4 – Kaynak: <a href="https://www.apple.com/swift/playgrounds/">Apple</a></figcaption></figure><p>Eğer siz de Playgrounds 4 ile çalışmak isterseniz en az iPadOS 15.2 sürümüne güncellediğinizden ve Playgrounds uygulamasının son sürümüne sahip olduğunuzdan emin olun.</p><p>💡<strong>İpucu: </strong>Playgrounds uygulamasında uygulama ikonunuzu aşağıda gördüğünüz gibi düzenleyebilirsiniz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*rvjj0bPnAvBfPxh42oLrXQ.gif" /></figure><p>Sanatımızı yapmak için bir tuvale ihtiyacımız var. 😄 Bu yüzden ilk olarak ContentView üzerinde bir değişiklik yapmadan CanvasView isminde yeni bir Swift dosyası oluşturup kendimize Apple Pencil ile çizim yapabileceğimiz bir görünüm, yani tuvalimizi oluşturmalıyız. Playgrounds uygulamasında yeni bir Swift dosyası oluşturmanız için gereken adımlar aşağıda yer almakta.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oQiPtPvoiERui7hny91aHQ.gif" /></figure><p>PencilKit şu anda SwiftUI üzerinde bulunmadığından daha önceki makalelerimizden birinde de bahsettiğimiz UIViewRepresentable protokolüne başvuracağız.</p><p>İlk adım yeni Swift dosyasına SwiftUI ve PencilKit Framework’lerini eklemek. Ardından aşağıdaki gibi CanvasView isminde yeni bir struct oluşturup içine PKCanvasView tipinde bir parametre ekliyoruz.</p><p>Kendi kendinize bunun oldukça kısa olduğunu düşünüyor olabilirsiniz. Ancak merak etmeyin, bu sadece başlangıç. Sonraki adımlarda birçok extension kullanarak bu struct yapılarının üstüne birçok ekleme yapacağız.</p><pre><strong>import</strong> SwiftUI<br><strong>import</strong> PencilKit</pre><pre><strong>struct</strong> CanvasView {<br>    @Binding <strong>var</strong> canvasView: PKCanvasView<br>}</pre><p>Gördüğünüz üzere yukarıda bir UIKit gürünümü olan, Binding bir PKCanvasView değişkeni ekliyoruz. Yani CanvasView , UIViewRepresentable protokolünü kullanarak SwiftUI ile kullanılabilir hale getireceğimiz ana UIKit görünümünü dışarıdan alacak. Sonraki adımlarda ContentView üzerinde PKCanvasView tipinde bir State değişkeni oluşturup CanvasView içine atayacağız. Doğal olarak bütün bu uğraşın nedenini düşünüyor olabilirsiniz.</p><p>Bu yöntem ile PKCanvasView UIKit görünümünün özelliklerine ContentView üzerinden kolayca erişebileceğiz. Mesela tuvali temizlemek, ya da arkadaşlarınızla paylaşmak için tuval üzerindeki çizimi dışa aktarmak istediğinizde! 😁</p><p>Sonraki adımda struct yapımızın bir extension aracılığıyla UIViewRepresentable protokolüne uymasını sağlıyoruz. Böylece CanvasView görünümünü SwiftUI ile kullanabileceğiz.</p><pre><strong>extension</strong> CanvasView: UIViewRepresentable {<br>  <strong>func</strong> makeUIView(context: Context) -&gt; PKCanvasView {<br>    <strong>// Varsayılan çizim aracını ayarlıyoruz:</strong><br>    canvasView.tool = PKInkingTool(.pen, color: .purple, width: 10)<br>    <strong>// Parmak ile çizime izin veriyoruz</strong><br>    canvasView.drawingPolicy = .anyInput</pre><pre>    <strong>return</strong> canvasView<br>}</pre><pre><strong>func</strong> updateUIView(_ uiView: PKCanvasView, context: Context) { }<br>}</pre><p>Yukarıda standard UIViewRepresentable yapısına ek olarak canvasView.tool parametresini ayarlayarak kullanıcı uygulamamızı ilk açtığında seçili olan çizim aracını belirliyoruz. Ardından canvasView.drawingPolicy parametresini yukarıdaki gibi ayarlayarak bütün giriş metodlarına izin veriyoruz. Böylece uygulamamızın Apple Pencil’a ihtiyaç duymadan çalışmasını sağlıyoruz.</p><p>Artık çizim yapmak için ihtiyacımız olan minimum kodu tamamladık. Şimdiyse ContentView.swift dosyasına geri dönüp ana arayüz için çalışalım.</p><p>İlk adım PencilKit teknolojisini bu dosyaya da bir import komutuyla eklemek olacak. Bunu SwiftUI ‘ın import komutundan hemen sonra eklemelisiniz.</p><pre><strong>import</strong> PencilKit</pre><p>Şimdi ContentView struct yapısına geçebiliriz. İçeriği aşağıdaki gibi gözükmeli. Daha önce de bahsettiğimiz gibi önce State olarak bir PKCanvasView görünümü tanımlıyor ve onu CanvasView görünümümüze atıyoruz. Aynı zamanda CanvasView görünümünü ilerleyen adımlarda ekleyeceğimiz temizleme ve paylaşma butonları için bir NavigationView içine yerleştirmeliyiz.</p><pre><strong>struct</strong> ContentView: View {<br>  <strong>// canvasView isimli bir UIKit PKCanvasView gürünümü tanımlıyoruz</strong><br>  @State <strong>private</strong> <strong>var</strong> canvasView = PKCanvasView()</pre><pre>  <strong>var</strong> body: <strong>some</strong> View {<br>    NavigationView {<br>      <strong>// Oluşturduğumuz UIViewRepresentable görünümünü ekliyor</strong><br>      <strong>// ve içine UIKit PKCanvasView görünümünü atıyoruz.</strong><br>      CanvasView(canvasView: $canvasView)<br>    }<br>    .navigationViewStyle(.stack)<br>  }<br>}</pre><p>🥳 Tebrikler! Uygulamanın temeli artık hazır. Uygulamanızı aşağıdaki gibi çalıştırıp çizim yapmayı hemen deneyebilirsiniz, ancak bir çizim uygulaması bundan çok daha fazlasına sahip olmalı. Hadi o zaman işe bir temizleme butonu ekleyerek devam edelim! 🙌</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0uVBwb-nRA4zhukMD3FgCw.gif" /></figure><h3>🧽 Tuvali Temizleme</h3><p>Bu işlem belkide tahmin ettiğinizden çok daha kolay olacak! İlk adım tabii ki bir temizleme butonu eklemek. 😁</p><p>Temizleme butonunu bir <em>tool bar </em>yani araç çubuğu üzerine ekleyeceğiz. Şimdi CanvasView görünümünüze bu niteleyicileri ekleyin, sonuç aşağıdaki gibi gözükmeli.</p><pre><strong>// ContentView içindeki CanvasView görünümü:</strong></pre><pre>CanvasView(canvasView: $canvasView)<br>  .toolbar {<br>    ToolbarItemGroup(placement: .navigationBarTrailing) {<br>      Button(action: { <br>      <strong>// Silme diyaloğunu görüntüleme kodu buraya gelecek</strong><br>      }) {<br>        Label(“Clear”, systemImage: “trash”)<br>      }<br>    }<br>  }</pre><p>Önce toolbar niteleyicisinin içine bir tane araç çubuğu içeriği, yani ToolBarItemGroup objesi ekliyoruz ve sağa yerleştiriyoruz.</p><p>Silme işlemi kalıcı olduğundan, kullanıcının butona yanlışlıkla dokunma olasılığına karşı silmeden önce kullanıcıya bir onay diyaloğu sunmalıyız. Bunun içinse ilk adım ContentView içine diyaloğun gösterilip gösterilmediğini kontrol eden bir State değişkeni eklemek.</p><pre>@State <strong>private</strong> <strong>var</strong> showingDeleteConfirmation = <strong>false</strong></pre><p>Harika! Şimdiyse butonun içindeki satır yorumu yerine bu kodu ekleyerek butona dokunulduğunda değişkenin değerinin true olarak ayarlanmasını sağlamalıyız.</p><pre>showingDeleteConfirmation = <strong>true</strong></pre><p>Sıra onay diyaloğunu eklemekte. Az önce kodladığımız butona aşağıda gördüğünüz şekilde .confirmationDialog niteleyicisini ekleyin.</p><pre>.confirmationDialog(“Clear canvas”, isPresented: $showingDeleteConfirmation) {<br>  <strong>// Temizleme butonu</strong><br>  Button(“Clear”, role: .destructive) {<br>    <strong>// UIKit PKCanvasView görünümünün çizimine yeni bir çizim atıyoruz</strong><br>    canvasView.drawing = PKDrawing()<br>  }<br>  <strong>// İptal butonu</strong><br>  Button(“Cancel”, role: .cancel) { }<br>} message: {<br>  <strong>// Diyalog mesajı</strong><br>  Text(“Do you want to delete all of your work? This cannot be undone.”)<br>}</pre><p>Eklediğimiz temizleme butonun action argümanı, doğrudan UIKit PKCanvasView görünümünün çizimi temsil eden drawing değişkenine erişip, değerini yeni bir çizime ayarlıyor. Böylece tuvalimizi temizlemiş oluyoruz.</p><p>İptal butonuna ise .cancel rolünü atadığımızdan action parametresine hiçbir şey eklememize gerek kalmıyor. SwiftUI bizim için bütün işi çözüyor.</p><p>Böylelikle artık tek tuşla bütün tuvalimizi temizleyebiliyoruz! 🙌</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xtyfdGPvol1FexHZ6qKVBQ.gif" /></figure><h3>🎨 Daha Fazla Araç!</h3><p>Siz de takdir edesiniz ki tek bir kalem, istediğiniz gibi bir çizim yapmak için yeterli olmayabilir. Şimdi bir adım daha ileri giderek uygulamamıza PencilKit’in sunduğu tüm araç takımını ekleyeceğiz. Bu farklı kalem seçenekleri ve renkler dışında silgi, seçim aracı, cetvel ve ileri/geri alma fonksiyonlarını da ekliyor. Hadi işe koyulalım!</p><p>Proje dosyalarından CanvasView.swift dosyasına geri dönün. İlk adım CanvasView struct yapısının içinde aşağıdaki gibi bir araç takımı, yani PKToolPicker objesi oluşturmak.</p><pre>@State <strong>private</strong> <strong>var</strong> toolPicker = PKToolPicker()</pre><p>Mükemmel! Bir sonraki adım ise elimizdeki bu araç takımını göstermek. Bunu sağlayacak metodu struct yapısına eklemek için aşağıdaki gibi yeni bir extension yazıyoruz. Ayrıca kullandığımız private anahtar kelimesi sayesinde extension yapısını içeriği, sadece bu struct içinden erişilebilir hale geliyor.</p><pre><strong>private</strong> <strong>extension</strong> CanvasView {</pre><pre>  <strong>// Araç takımını gösteren metot</strong><br>  <strong>func</strong> showToolPicker() {<br>    <strong>// CanvasView aktifken araç takımını göster<br></strong>    toolPicker.setVisible(<strong>true</strong>, forFirstResponder: canvasView)<br>    <strong>// CanvasView görünümünü araç değişiminde güncelle</strong><br>    toolPicker.addObserver(canvasView)<br>    <strong>// CanvasView görünümünü ana görünüm yap</strong><br>    canvasView.becomeFirstResponder()<br>  }<br>}</pre><p>Metodumuzun içinde ilk olarak araç takımımızın görünürlüğünü CanvasView görünürlüğüne bağlıyoruz. Ardından addObserver metodu ile CanvasView görünümünün araç takımında meydana gelen güncellemelerden haberdar olduğundan emin oluyoruz. Son olarak da CanvasView görünümünü ana görünüm olarak ayarlayarak araç takımımızın göründüğünden emin oluyoruz.</p><p>Şimdi de fonksiyonumuzu aşağıdaki gibiUIViewRepresentable protokolüne uyan extension içindeki makeUIView metodunun içine, return komutundan hemen önce çağırıyoruz.</p><pre>showToolPicker()</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SH10ITZ4eLkfuC_VF2wu8Q.gif" /></figure><p>🥳 Artık uygulamanızı çalıştırdığınızda Apple Notlar uygulamasından alışık olduğumuz PencilKit araç takımını kullanabilirsiniz.</p><h3>🖼 Sanatınızı Paylaşın!</h3><p>Artık eserinizi oluşturdunuz, ve onu dünya ile paylaşma vakti! Belki de en önemli adım olan bu bölümde, uygulamamıza ekleyeceğimiz paylaşma menüsü sayesinde sanatınızı kaydedebilecek ve herkesle paylaşabileceksiniz. Hadi işe koyulalım! 🙌</p><p>Paylaşma menüsü de SwiftUI’da bulunmadığından, yine UIViewRepresentable kullanmamız gerek. İlk adım ShareSheet.swift isminde yeni bir dosya oluşturmak, ardından aşağıdaki gibi ShareSheet isminde bir struct yapısı oluşturuyoruz — tabii ki UIViewRepresentable protokolünde.</p><pre><strong>struct</strong> ShareSheet: UIViewControllerRepresentable {<br>  <strong>// Menünün görünürlüğünü kontrol ediyor</strong><br>  @Environment(\.presentationMode) <strong>private</strong> <strong>var</strong> presentationMode<br>  <strong>// Paylaşılacak içerik</strong><br>  <strong>let</strong> activityItems: [<strong>Any</strong>]</pre><pre>  <strong>func</strong> makeUIViewController(context: UIViewControllerRepresentableContext&lt;ShareSheet&gt;) -&gt; UIActivityViewController {<br>    <strong>// Paylaşma görünümü objesini oluşturuyoruz</strong><br>    <strong>let</strong> viewController = UIActivityViewController(activityItems: activityItems, applicationActivities: <strong>nil</strong>)<br>    <strong>// Paylaşma tamamlandığında çalışan metod</strong><br>    viewController.completionWithItemsHandler = { (_,_,_,_) <strong>in<br>      // Menüyü kapatıyoruz</strong><br>      presentationMode.wrappedValue.dismiss()<br>    }<br>    <strong>return</strong> viewController<br>  }</pre><pre><strong>func</strong> updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext&lt;ShareSheet&gt;) { }<br>}</pre><p>İlk olarak struct yapımızda menünün görünürlüğünü kontrol eden bir Environment değişkeni ve paylaşılacak içeriği tutan bir değişken oluşturuyoruz.</p><p>Ardından UIViewRepresentable protokol metotlarında biri olan makeUIViewController metodunun içinde paylaşma menüsü ojesini oluşturuyoruz. Sonra da paylaşma menüsünün bir closure ‘ı olan completionWithItemsHandler içerisine daha önce oluşturduğumuz değişkeni kullanarak menünün gizlenmesi için gereken kodu yazıyoruz. Bu closure , paylaşma iştemi tamalandıktan sonra çalıştırılıyor, böylece paylaşma tamamlandıktan sonra menünün kendiliğinden kapanmasını sağlıyoruz.</p><p>Paylaşma menüsü SwiftUI için artık hazır, şimdiyse sıra onu çizimimizi paylaşmak için ana görünüme eklemek. ContentView.swift dosyasına geri dönüp menünün görünürlüğünü kontrol eden aşağıdaki değişkeni ContentView struct yapısının içine, hemen showingDeleteConfirmation değişkenin altına ekleyin.</p><pre>@State <strong>private</strong> <strong>var</strong> showingShareSheet = <strong>false</strong></pre><p>Ardından daha önce oluşturduğumuz araç çubuğu, yani toolbar içerisine paylaş butonunu ekliyoruz. Aşağıdaki kodu ToolbarItemGroup içine ilk sıraya ekleyin., böylece paylaş butonu silme butonunun soluna yerleşecek.</p><pre>Button(action: {<br>  <strong>// Paylaş menüsünü görünür yapıyoruz</strong><br>  showingShareSheet = <strong>true<br></strong>}) {<br>  Label(“Share Drawing”,systemImage: “square.and.arrow.up”)<br>}</pre><p>Aynı silme onay diyaloğunda olduğu gibi, bu butonun action parametresinde de görünürlüğü kontrol eden değişkenin değerini true olarak ayarlayıp butona dokunulduğunda menüyü açıyoruz.</p><p>Harika! Şimdi de bu değişkenin kontrol edeceği sheet görünümünü ekleyelim, onun içerisine de paylaşma menüsünü. 😄 toolbar niteleyicisinin hemen altında yer almalı.</p><p><strong>💡 İpucu: </strong>Swift Playgrounds ve Xcode editöründe bir standart, köşeli ya da süslü bir parantezin eşini kolayca bulmak için üzerine çift tıklayabilirsiniz!</p><pre>.sheet(isPresented: $showingShareSheet) {<br><strong>// Paylaş menüsü</strong><br>ShareSheet(activityItems: [canvasView.drawing.image(from: canvasView.bounds, scale: UIScreen.main.scale)])<br>}</pre><p>Yukarıda canvasView objesinin barındırdığı çizimi resim dosyası olarak ShareSheet görünümünün paylaşılacak içerik parametresine atıyoruz. Böylece çizimi diğer uygulamalarla bir fotoğraf olarak paylaşabiliyoruz. Daha da iyisi, dışarı aktarılan resim PNG formatında olduğundan tamamen saydam bir arka plana sahip!</p><p>Artık çalışmalarınızı kolayca cihazınıza kaydedebilir, ve sevdiklerinizle paylaşabilirsiniz!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_TCFghdtBsCZNwteSJ8CKQ.gif" /></figure><p>🥳 Tebrikler! Çizim uygulamanız artık hazır. Unutmayın ki sadece bu çizim uygulamasıyla sınırlı kalmak zorunda değilsiniz. PencilKit teknolojisini aynı zamanda hali hazırdaki bir projenize de bu adımları takip ederek entegre edebilirsiniz. 😉</p><p>Umuyoruz ki bu makale size faydalı olmuştur ve yeni bilgiler öğrenmişsinizdir. 😌 Sorularınız olursa bize yourum yazmayı unutmayın, ve tabii ki bir sonraki yazımıza kendinize çok iyi bakın. Harika bir 2022 geçirmeniz dileğiye…</p><p>Bizi daha yakından takip etmek istiyorsanız, sosyal medya hesaplarımıza aşağıdan ulaşabilirsiniz!</p><p><a href="https://twitter.com/turkishkit"><strong>Twitter</strong></a><strong> | </strong><a href="https://www.instagram.com/turkish.kit/"><strong>Instagram</strong></a><strong> | </strong><a href="https://www.facebook.com/turkishkit"><strong>Facebook</strong></a></p><figure><a href="https://medium.com/turkishkit/swiftui/home"><img alt="" src="https://cdn-images-1.medium.com/max/700/0*Sb0hseLpzfPV_K6Z.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e7634014b39a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/turkishkit/swiftui-pencilkit-ile-%C3%A7izim-e7634014b39a">SwiftUI: PencilKit ile Çizim</a> was originally published in <a href="https://medium.com/turkishkit">TalentKit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SwiftUI: Map]]></title>
            <link>https://medium.com/turkishkit/swiftui-map-e5683a14e957?source=rss----19443271f3c7---4</link>
            <guid isPermaLink="false">https://medium.com/p/e5683a14e957</guid>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[turkishkit]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[apple]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Baran Önen]]></dc:creator>
            <pubDate>Sat, 04 Sep 2021 06:04:45 GMT</pubDate>
            <atom:updated>2021-09-04T06:04:45.708Z</atom:updated>
            <content:encoded><![CDATA[<h4>Map elemanını kullanarak uygulamanıza harita görüntüleri ekleyin!</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2WBb448svAmg8xD1chl1Cg.png" /></figure><p>Herkese merhaba! Bu yazımızda, uygulamanıza Map elemanını kullanarak Apple Maps tasarımında haritalar eklemeyi göstereceğim.</p><p>MapKit hakkında daha fazla bilgi veya UIKit ile yazılmış örnekler için <a href="https://medium.com/turkishkit/mapkit/home">burayı ziyaret edebilirsiniz.</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XTEPhtkgmCI_BWYbgNq5cA.png" /></figure><p>Öncelikle bir iOS uygulaması oluşturalım. İsim olarak “Map”i kullanabilirsiniz.</p><p>Sonra, uygulamamızda kullanacağımız MapKit‘i “import” edelim.</p><pre><strong>import</strong> SwiftUI<br><strong>import</strong> MapKit</pre><p>Map elemanını uygulamamıza eklemek için gereken sadece bir adım kaldı. Bu da haritanın nereyi göstereceğini seçmek.</p><p>Bunu yapabilmek için bir MKCoordinateRegion oluşturmamız gerekiyor. Londra şehrini görüntülemek için aşağıdaki değerleri kullanabiliriz.</p><pre>@State <strong>private</strong> <strong>var</strong> region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))</pre><p>Burada latitude ve longitude değerleri konumu gösterirken latitudeDelta ve longitudeDelta değerleri görüntünün ne kadar geniş olacağını gösteriyor.</p><p>Artık Map elemanını uygulamaya ekleyebiliriz.</p><pre>Map(coordinateRegion: $region)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dOyrbtdwTajqBCUnod_bAg.png" /></figure><p>region değişkenini @State olarak deklare etmemizin sebebi, kullanıcının haritayı kaydırdıkça bu değişkenin güncellenecek olması.</p><p>Eğer alanın değiştirilebilmesini istemiyorsanız, Map&#39;i aşağıdaki gibi de kullanabilirsiniz:</p><pre>Map(coordinateRegion: .constant(MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))), interactionModes: [])</pre><p>Bu şekilde görünümde hiç bir fark olmayacak. Ancak, interactionModes parametresinde hiç bir etkileşim yöntemi tanımadığımız için haritanın konumu değiştirilemeyecek.</p><pre>Map(coordinateRegion: $region, interactionModes: [.zoom])</pre><p>Bu şekilde kullanıldığında ise kullanıcı haritanın konumunu yine değiştiremeyecek. Ancak, bu konuma uzak veya yakından bakabilecek.</p><p>Bu şekilde uygulamanıza harita görüntüleri ekleyebilirsiniz. Bir sonraki yazıda görüşmek üzere! 👋</p><p>Bizi daha yakından takip etmek istiyorsanız, sosyal medya hesaplarımıza aşağıdan ulaşabilirsiniz!</p><p><a href="https://twitter.com/turkishkit"><strong>Twitter</strong></a><strong> | </strong><a href="https://www.instagram.com/turkish.kit/"><strong>Instagram</strong></a><strong> | </strong><a href="https://www.facebook.com/turkishkit"><strong>Facebook</strong></a></p><figure><a href="https://medium.com/turkishkit/swiftui/home"><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*lWeUMtR0qo7sbDSp.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e5683a14e957" width="1" height="1" alt=""><hr><p><a href="https://medium.com/turkishkit/swiftui-map-e5683a14e957">SwiftUI: Map</a> was originally published in <a href="https://medium.com/turkishkit">TalentKit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SwiftUI: .mask()]]></title>
            <link>https://medium.com/turkishkit/swiftui-mask-3f9d098b11b1?source=rss----19443271f3c7---4</link>
            <guid isPermaLink="false">https://medium.com/p/3f9d098b11b1</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[turkishkit]]></category>
            <category><![CDATA[apple]]></category>
            <dc:creator><![CDATA[Baran Önen]]></dc:creator>
            <pubDate>Fri, 27 Aug 2021 14:03:09 GMT</pubDate>
            <atom:updated>2021-08-27T14:03:07.163Z</atom:updated>
            <content:encoded><![CDATA[<h3>SwiftUI: mask()</h3><h4>Uygulamanızdaki View‘ları birbirleriyle maskeleyerek sadece bir kısmının görünmesini sağlayın!</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xtfodipvVZDdQefjKoneTw.png" /></figure><p>Herkese merhaba! Bu yazıda, bir View‘un sadece başka bir View ile ortak olan piksellerinin gösterilmesini sağlayan mask “modifier”ından bahsedeceğim.</p><p>Aynı işlemin <a href="https://medium.com/turkishkit/uikit/home">UIKit</a> versiyonu için aşağıdaki makaleyi takip edebilirsiniz:</p><p><a href="https://medium.com/turkishkit/imageview-maskeleme-f215796822e5">UIKit: ImageView Maskeleme</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*p108TcjqlCKm8IBgpLKTuw.png" /></figure><p>Bir iOS projesi oluşturarak başlayalım. Projenin adı için “Mask”ı kullanabilirsiniz.</p><p>Şimdi, internetteki bir URL aracılığıyla uygulamaya görüntü eklemek için bu sene tanıtılan AsyncImage‘ı kullanacağız.</p><p>Bu eleman hakkında daha fazla bilgi için aşağıdaki makaleye göz atabilirsiniz:</p><p><a href="https://medium.com/turkishkit/wwdc21-asyncimage-6e561f348f7c">WWDC21: AsyncImage</a></p><p>Aşağıdaki kodu projeye ekleyelim:</p><pre>AsyncImage(url: URL(string: “https://source.unsplash.com/random&quot;)) { image <strong>in<br>   </strong>image.resizable()<br>} placeholder: {<br>   ProgressView()<br>}.frame(width: 300, height: 300)</pre><p>Burada kod hata verirse, projenin ayarlarına gelerek hedef sürümü iOS 15.0 (veya üstü) olarak değiştirin.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-daQjV0BVyeEH9Tdo2n1iQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DDGNKVcRUN6624_Im2D2NA.png" /></figure><p>Artık Unsplash’den alınan rastgele bir resim, uygulamamızda gösteriliyor. Şimdi yapmak istediğimiz şey, kullanılan görseli TurkishKit yazısının arkasında maskelemek.</p><p>Bunun için aşağıdaki “modifier”ı AsyncImage‘ın sonuna ekleyelim.</p><pre>.mask {<br>   Text(&quot;TurkishKit&quot;)<br>      .font(.largeTitle)<br>      .fontWeight(.black)<br>}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EE4ZpsbZqubkX_dl7zuxcQ.png" /></figure><p>İstediğimiz görüntüye kısa bir sürede ulaştık.</p><p>Bu şekilde bazı karışık arayüz elemanlarını oldukça kolay bir şekilde kodlayabilirsiniz.</p><p>Üstteki yöntemle metinlerin yanı sıra, görselleri de birbirinin üzerine maskeleyebilirsiniz. Örneğin aşağıda, internetten rastgele alınan görsel, TurkishKit logosu şeklinde gösteriliyor.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BMpoG_1WqgNM061Af7hJzQ.png" /></figure><p>Kod ise aşağıdaki şekilde:</p><pre>.mask {<br>   Image(&quot;TKLogo&quot;)<br>      .resizable()<br>      .frame(width: 300, height: 247)<br>}</pre><p>.mask() “modifier”ı hakkında bilmeniz gereken her şey bu kadardı. Bir sonraki makalede görüşmek üzere!</p><p>Bizi daha yakından takip etmek istiyorsanız, sosyal medya hesaplarımıza aşağıdan ulaşabilirsiniz!</p><p><a href="https://twitter.com/turkishkit"><strong>Twitter</strong></a><strong> | </strong><a href="https://www.instagram.com/turkish.kit/"><strong>Instagram</strong></a><strong> | </strong><a href="https://www.facebook.com/turkishkit"><strong>Facebook</strong></a></p><figure><a href="https://medium.com/turkishkit/swiftui/home"><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*e3hSdSXlDtDTckWz.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3f9d098b11b1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/turkishkit/swiftui-mask-3f9d098b11b1">SwiftUI: .mask()</a> was originally published in <a href="https://medium.com/turkishkit">TalentKit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SwiftUI: ViewModifier]]></title>
            <link>https://medium.com/turkishkit/swiftui-viewmodifier-d13b8bfced56?source=rss----19443271f3c7---4</link>
            <guid isPermaLink="false">https://medium.com/p/d13b8bfced56</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[turkishkit]]></category>
            <category><![CDATA[ios-app-development]]></category>
            <category><![CDATA[swiftui]]></category>
            <dc:creator><![CDATA[M. Bertan Tarakçıoğlu]]></dc:creator>
            <pubDate>Wed, 25 Aug 2021 14:03:12 GMT</pubDate>
            <atom:updated>2021-08-25T14:03:06.662Z</atom:updated>
            <content:encoded><![CDATA[<h4>ViewModifier ile UI elemanlarınızı nasıl değiştirebileceğinizi keşfedin!</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZoIOkHxrpLT7FKQITsH8bw.png" /></figure><p>👋 Merhaba sevgili TurkishKit okuyucuları! Bu yazımızda temiz kod yazma yolunda önemli bir adım olan bir konsepti inceliyoruz: ViewModifier.</p><h3>Giriş</h3><p>SwiftUI projenizde bir sürü görünüme tekrar tekrar aynı “modifier”ları yazdığınızı farkediyordunuz, kodunuz uzuyor ve okunması zorlaşıyor. Eğer bu siz iseniz doğru makaleyi okuyorsunuz. 😄 Tekrar tekrar aynı şeyi yazmaktansa neden istediğimiz bütün UI “modifier”larını bir niteleyicide toplamayalım ki?</p><p>Aşağıda örnek bir Label görünümü yer almakta.</p><pre>Label(&quot;SwiftUI&quot;, systemImage: &quot;swift&quot;)<br>    .font(.system(size: 50, weight: .semibold, design: .rounded))<br>    .foregroundColor(.white)<br>    .padding()<br>    .background(LinearGradient(colors: [.indigo, .mint], startPoint: .topLeading, endPoint: .bottomTrailing))<br>    .cornerRadius(25)<br>    .shadow(radius: 15)</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7rOV3LAHp3Z5_lFliI0dEw.png" /></figure><p>Şimdi burada gördüğünüz bütün niteleyicileri bir tanesinin içinde topluyoruz. Bunun için SwiftUI’daki ViewModifier protokolünü kullanacağız — bunlar da SwiftUI görünümleri gibi struct kullanılarak oluşturuluyor.</p><pre><strong>struct</strong> GradientTag: ViewModifier {<br>    <strong>func</strong> body(content: Content) -&gt; <strong>some</strong> View {<br>        content<br>          .font(.system(size: 50, weight: .semibold, design: .rounded))<br>          .foregroundColor(.white)<br>          .padding()<br>          .background(LinearGradient(colors: [.indigo, .mint], startPoint: .topLeading, endPoint: .bottomTrailing))<br>          .cornerRadius(25)<br>          .shadow(radius: 15)<br>    }<br>}</pre><p>Özel nitelecinin bütün niteleyicilerini body fonksiyonunun content parametresine uyguluyoruz. content parametresi, özel niteleyicinizin uygulandığı görünümün kendisini; body fonksiyonunun içeriği de niteleyicinin görünümüze uygulandıktan sonraki yeni halini temsil etmekte — yani standart bir SwiftUI görünümü.</p><p>Özel niteleyicinizi görünümlerinize uygulamak için ihtiyacınız olan şey… kendisi başka bir niteleyici olan .modifier.</p><pre>// ContentView.swift:</pre><pre><strong>struct</strong> ContentView: View {<br>    <strong>var</strong> body: <strong>some</strong> View {<br>        Label(“SwiftUI”, systemImage: “swift”)<br>            .modifier(GradientTag())<br>    }<br>}</pre><h3>Parametreler!</h3><p>Sonraki adımlarda SwiftUI’ın View protokolüne bir Extension oluşturarak .modifier niteleyicisine olan ihtiyaçtan kurtulacağız ama ondan önce bir adım daha ileri gidip özel niteleyicilerinize parametre eklemeyi keşfedelim.</p><p>Aslında temel mantığı SwiftUI görünümlerine parametre eklemekle tamamen aynı. Niteleyicimizin yeni haline Color tipinde değerlere sahip bir dizi parametresi ekliyoruz ve LinearGradient görünümüne atıyoruz. Böylece gradyan renklerini istediğimiz gibi özelleştirebileceğiz.</p><pre>// GradientTag.swift</pre><pre><strong>struct</strong> GradientTag: ViewModifier {<br>    <strong>let</strong> gradientColors: [Color]</pre><pre>    <strong>func</strong> body(content: Content) -&gt; <strong>some</strong> View {<br>        content<br>          .font(.system(size: 50, weight: .semibold, design: .rounded))<br>          .foregroundColor(.white)<br>          .padding()<br>          .background(LinearGradient(colors: gradientColors, startPoint: .topLeading, endPoint: .bottomTrailing))<br>          .cornerRadius(25)<br>          .shadow(radius: 15)<br>    }<br>}</pre><pre>// ContentView.swift</pre><pre><strong>struct</strong> ContentView: View {<br>    <strong>var</strong> body: <strong>some</strong> View {<br>    Label(“SwiftUI”, systemImage: “swift”)<br>        .modifier(GradientTag(gradientColors: [.indigo, .mint]))<br>    }<br>}</pre><h3>View Extension</h3><p>Evet şimdi size daha önce bahsettiğim gibi .modifier niteleyicisinden kurtulma zamanı. 😄 Artık .modifier(GradientTag(...)) yerine .gradientTag(...) kullanacağız!</p><p>Burada yaptığımız</p><pre>// GradientTag.swift dosyasına ekleyin:</pre><pre><strong>extension</strong> View {<br>    <strong>func</strong> gradientTag(gradientColors: [Color]) -&gt; <strong>some</strong> View {<br>        <strong>self</strong>.modifier(GradientTag(gradientColors: gradientColors))<br>    }<br>}</pre><pre>// ContentView.swift</pre><pre><strong>struct</strong> ContentView: View {<br>    <strong>var</strong> body: <strong>some</strong> View {<br>        Label(“SwiftUI”, systemImage: “swift”)<br>            .gradientTag(gradientColors: [.indigo, .mint])<br>    }<br>}</pre><p>Kod gitgide uzuyormuş gibi gelebilir, ancak büyük projelerde ana dosyaları kalabalıklaştırmamak ve okunabilirliği artırmak için yaptığımız şey oldukça önemli.</p><p>Şimdilik bizden bu kadar. Umuyorum ki burada öğrendikleriniz işinize yarar, ve tabii ki bir sonraki makaleye kadar kendinize çok iyi bakın. 🙂</p><p>Bizi daha yakından takip etmek istiyorsanız, sosyal medya hesaplarımıza aşağıdan ulaşabilirsiniz!</p><p><a href="https://twitter.com/turkishkit"><strong>Twitter</strong></a><strong> | </strong><a href="https://www.instagram.com/turkish.kit/"><strong>Instagram</strong></a><strong> | </strong><a href="https://www.facebook.com/turkishkit"><strong>Facebook</strong></a></p><figure><a href="https://medium.com/turkishkit/swiftui/home"><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zFqXYYG3djlFx8XywcuqBg.png" /></a></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d13b8bfced56" width="1" height="1" alt=""><hr><p><a href="https://medium.com/turkishkit/swiftui-viewmodifier-d13b8bfced56">SwiftUI: ViewModifier</a> was originally published in <a href="https://medium.com/turkishkit">TalentKit</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>