<?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[Stories by Ilter Cengiz on Medium]]></title>
        <description><![CDATA[Stories by Ilter Cengiz on Medium]]></description>
        <link>https://medium.com/@iltercengiz?source=rss-ef4293c548f5------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*5GPhZKesbJzPK4-ndy2cBQ.jpeg</url>
            <title>Stories by Ilter Cengiz on Medium</title>
            <link>https://medium.com/@iltercengiz?source=rss-ef4293c548f5------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 17:08:42 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@iltercengiz/feed" 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 ile Birden Fazla Proje Kurulumu]]></title>
            <link>https://medium.com/nsistanbul/xcode-workspace-ile-birden-fazla-proje-kurulumu-4b410226635f?source=rss-ef4293c548f5------2</link>
            <guid isPermaLink="false">https://medium.com/p/4b410226635f</guid>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[workspace]]></category>
            <category><![CDATA[framework]]></category>
            <category><![CDATA[carthage]]></category>
            <category><![CDATA[dependencies]]></category>
            <dc:creator><![CDATA[Ilter Cengiz]]></dc:creator>
            <pubDate>Mon, 14 May 2018 08:15:39 GMT</pubDate>
            <atom:updated>2019-05-17T12:59:34.584Z</atom:updated>
            <content:encoded><![CDATA[<p>Bu yazımda Xcode workspace kullanarak birden fazla proje içeren bir iOS uygulaması projesi kurulumu nasıl yapılır onu anlatacağım. Bu tekniği sadece iOS uygulamaları için değil, macOS, tvOS veya bu platformların bir veya birkaçını destekleyen projelerinizde kod paylaşımı yapmak için kullanabilirsiniz.</p><p>Peki amaç nedir?</p><ul><li>Bu yaklaşım modüler düşünmenizi sağlar. Projenizi birden fazla modüle ayırmanız daha iyi arayüzler ve sorumluluklar tasarlamanızı sağlar.</li><li>Her modül ayrı bir ürün olacağından dolayı her birinin kendi test setleri olacak ve test süreçlerinizde zaman kazanmanızı sağlayacak.</li><li>Bir başka fayda ise yeniden kullanılabilirlik. Her modül farklı projelerde yeniden kullanılabilir. Bu da bize hem geliştirme sürecinde hem de bakım sürecinde zaman kazandırır.</li></ul><p>Bu anlatımımda Xcode 9.3 kullandım. Bu versiyonda eski versiyonlara kıyasla çok ufak bir fark var ve bu farkı yeri geldiğinde belirteceğim. Eski versiyonlardan birini kullanıyorsanız yine de takip edebilirsiniz.</p><p>Hadi başlayalım!</p><h4>Workspace</h4><p>Boş bir workspace oluşturarak başlıyoruz. Xcode File menüsünden yeni bir workspace oluşturun ve istediğiniz bir dizin içerisine kaydedin.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*nZ7Va367OE_M0f7grbaitg.png" /></figure><p>Masaüstü dizinimde MultiProject adlı bir dizin oluşturdum ve yine aynı isimle bir workspace oluşturup içerisine kaydettim.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*aUx1-OEh3xdkG1XXNu7hLA.png" /></figure><p>Ve bu da boş workspace’in kendisi.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*6M4i9lmdx-Co8cGTDBRPdQ.png" /></figure><p>Şu an için hiçbir şey yok. Ne bir proje, ne bir kaynak kod, ne bi şema.</p><h4>Uygulama projesini ekleme</h4><p>Yeni mükemmel uygulama fikrimiz için bir iOS uygulama projesi oluşturalım.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Jj_aqJatR1usbsJ3pncj-Q.png" /></figure><p>Yine Xcode’un File menüsünü kullanıyoruz. Bu menüden Project seçtiğimiz zaman aşağıdaki ekranı görüyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*LrBlLmWwBRWVoQPfPMPLlw.png" /></figure><p>Arkadaki pencere az önce oluşturduğumuz workspace’e ait değil, ama birazdan o pencereye geri döneceğiz. iOS uygulamasının kendisiyle bir işimiz olmadığı için ve işleri basit tutmak için Single View App seçeceğini seçebiliriz. Next dedikten sonra bir sonraki ekrandaki bilgileri tercihinize göre doldurun ve yine ilerleyin. Bir sonraki adımda projeyi nereye kaydetmek istediğimizi soran aşağıdaki ekranı görüyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*_NKYG9iWW02uMrUHzj8cCQ.png" /></figure><p>Tam olarak bu noktada yeni oluşturduğumuz projeyi, bir önceki adımda oluşturduğumuz boş workspace’e ekliyoruz. Projeyi başka bir dizinde kaydetmek yerine, dizin seçimi ekranının alt kısmındaki Add to listesini açarak workspace’imizi seçiyoruz. Bir dip not, bu listede workspace’imizi görebilmemiz için workspace’in hali hazırda açık olması gerekiyor.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*TktjLgd9hvyWofhXi9AoSA.png" /></figure><p>Add to kısmında workspace’imizi seçtikten sonra Group kısmının da güncellendiğini görüyoruz. Bu kısımda workspace’imizin seçili olması, projeyi workspace hiyerarşimizde ilk seviyede göreceğimiz anlamına geliyor. Create diyoruz ve bu ekranın kapanıp projemizin workspace’imizde açıldığını görüyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*lanNgpzDRWMtC8evJkzvYA.png" /></figure><p>Bu noktada elimizde neler var bir bakalım. Bir workspace’imiz var ve bu workspace’te bir projemiz var. Bu projemizde ise bir iOS uygulama, bir test ve bir UI test ürünlerimiz var (‘target’ daha isabetli nasıl Türkçe’ye çevrilir bilen varsa paylaşsın lütfen 😅). Projemizi workspace’e ekledikten sonra uygulamamızın şemasının eklendiğini de sol üstten görebilirsiniz. Şu an için bu ekran yeni bir proje açmışız gibi duruyor, workspace olduğunu bilmesek aradaki farkı söyleyemeyiz.</p><h4>Framework projesini ekleme</h4><p>Workspace’imize bir başka proje daha ekleyerek gerçekten workspace gibi görünmesini sağlayalım. Uygulama projesini eklerken izlediğimiz adımların aynısını izleyeceğiz. Tek fark, uygulama değil framework projesi eklememiz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*2IQ_1KSeaW6P9L5fWWX69A.png" /></figure><p>Yine Xcode bize yeni projemizi nereye kaydetmesini istediğimizi sorduğunda Add to ve Group kısmında workspace’imizin seçili olduğundan emin olun.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Way-chncBx_qPSEAPwR4RA.png" /></figure><p>Workspace’imizi seçtikten sonra, Xcode hem uygulama projemizin dizinini, hem workspace dosyamızı, hem de framework projemizin dizinini aynı dizin altında yan yana koymuş olacak. Create diyerek aşağıdaki ekrana dönüyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*8qiQbp2OOa2il35qgYXMFg.png" /></figure><p>İşte şimdi workspace’e benzedi. 😄</p><h4>Framework test sürüşü</h4><p>Şimdiye kadar her şey yolunda, fakat hiç kodlama yapmadık. Daha sonra uygulamamızda kullanmak üzere AwesomeAPI framework’ümüzde yeni bir sınıf oluşturalım.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*xdwI2_9Eh0elDyJeF-oTnA.png" /></figure><p>Burada AwesomeAPIClient adında bir sınıf oluşturduk ve static değişken tanımlayarak ‘singleton’ yaptık. Sonra testRun adında bir fonksiyon tanımladık. <strong>Hem sınıfı, hem değişkeni, hem de fonksiyonu </strong><strong>public tanımladığımıza dikkat edelim.</strong> Bu sınıf AwesomeAPI framework’ümüze ait olduğu için ve framework’ü eklediğimiz modüllerden kullanılmasını istediğimiz için bu parçaları public tanımlamamız gerekiyor.</p><h4>Framework’ü uygulamamız ile bağlama</h4><p>Uygulama tarafına geçelim ve framework’ümüzü kullanalım.</p><p>İlk önce uygulamamıza framework’ümüzü bağlamamız gerekiyor (linking). Fakat bununla beraber framework’ümüzün uygulamamıza gömülü olmasını belirtmemiz de gerekiyor (embed). Bu sayede uygulamamız sanki sistem tarafından sağlanmış bir framework gibi kendi framework’ümüzü kullanabilecek.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*emLG69PUq4SLsHmBbuQ0eg.png" /></figure><p>Uygulamamızın projesi seçili iken General sekmesinde Embedded Binaries bölümündeki +’ya basarak yukarıdaki ekranı açın. Listeden AwesomeAPI.framework seçin ve Add diyin. Bu şekilde Xcode’a framework’ümüzün uygulamamızı derlerken uygulamamıza gömülü olmasını istediğimizi belirtmiş oluyoruz. Ve gömülü olmasını belirtmemizin sebebi açıkça uygulamamızda kullanmak istediğimiz olduğu için, Xcode aynı zaman da Linked Frameworks and Libraries kısmına da ekliyor. Bu listede yer alıyor olması uygulamamızda kullanılabilir olması için yeterli.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*corF30ZotLNDp1GGnHXyKg.png" /></figure><p>Framework’ümüzün soldaki Project navigator kısmına da eklendiğine dikkat edin. Yazımın başında belirttiğim Xcode 9.3 ve eski sürümler farkı tam olarak burada. Xcode, eski versiyonlarında, aynı workspace içerisindeki bir framework’ü bir önceki adımdaki gibi Embedded Binaries bölümüne eklememize olanak vermiyordu. Xcode 9.3 versiyonu ile gelen proje ve workspace formatındaki yenilikler buna olanak sağlıyor artık (sağ paneldeki Project Format kısmından proje formatınızı doğrulayabilirsiniz).</p><p>Maalesef Xcode bütün güzellikleri aynı anda vermiyor ¯\_(ツ)_/¯. Bu şekilde eklediğimiz zaman proje altında hiçbir şekilde yerinden oynatamadığımız (sırasını değiştirmek haricince) bir framework referansı ile kalıyoruz. Projeye sağ tıklayıp New Group without Folder seçeneğinden yeni bir grup içerisine framework’ümüzü sürüklemeyi deneyin ve aynı referanstan bir tane daha oluşturacağını göreceksiniz. Üstelik bu yeni referans bağladığımız ve gömülü olmasını belirttiğimiz referansla da aynı değil.</p><p>Eğer benim gibi obsesif takıntılı değilseniz ve ‘ben bu şekilde de idare ederim’ diyorsanız bu şekilde bırakabilirsiniz. Ama projeniz daha düzenli olsun istiyorsanız, eski usül eklememiz gerekiyor. Eğer düzenli yolu seçiyorsanız öncelikle bu yerinden oynatamadığımız referansımıza sağ tıklayın ve silin. Bu hamle framework’ümüzün General sekmesindeki Embedded Binaries ve Linked Frameworks and Libraries listelerinden de silinmesine sebep olacak ama birazdan tekrar ekleyeceğiz. Projemize sağ tıklayın ve New Group without Folder seçeneğinden yeni bir grup oluşturun (ben tercihen Vendor ismini kullanıyorum). Sonra bu grup içerisine framework projemizi (AwesomeAPI) sürükleyip bırakın. Aşağıdaki ekranı görüyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*gDzK1Z5IpvnlxEthvtQepA.png" /></figure><p>Copy items if needed seçeneğinin <strong>seçili olmadığına</strong> emin olun. Sonrasında yine Embedded Binaries bölümünden +’ya basarak aşağıdaki framework seçim ekranını açıyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*W4xB27ftUzNgwqSEXuEMWg.png" /></figure><p>Listeye dikkat ederseniz aynı framework’ün iki kere listelendiğini göreceksiniz. Birisi workspace’imiz altındaki projede listeleniyor, diğeri ise iOS uygulamamızın projesine eklediğimiz yine aynı proje altında listeleniyor. Biz ikincisini seçiyoruz ve bu sayede ekstra bir referans eklenmemiş oluyor.</p><blockquote>17.05.2019</blockquote><blockquote><strong>Xcode 10.2.1 Güncellemesi</strong></blockquote><blockquote>Yukarıda bahsettiğim sıkıntı tam olarak hangi versiyonda çözüldü bilmiyorum fakat yakın zamanda Xcode 10.2.1 versiyonu ile denediğimde artık projenin altındaki diğer proje referansına gerek kalmadığını gözlemledim. Ayrıca projenin yapısını düzenli tutmak da mümkün.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u0ZpXYFP5i5H_3ZwZIRWiw.png" /><figcaption>Framework uygulamanın projesinde referans edilmiş halde</figcaption></figure><blockquote>Yukarıdaki ekran görüntüsünde Vendor grubunun boş olduğuna dikkat edin. Yani iç içe referans ettiğimiz projemiz silinmiş durumda. Aynı zamanda AwesomeAPI.framework’ü için de bir referansımız var. Yukarıda bahsettiğim adımları takip ettikten sonra tek yapmamız gereken, eklenen framework referansını dilediğimiz bir gruba <strong>⌘ command tuşuna basılı tutarken</strong> sürükleyip bırakmak. Bu detay önemli, çünkü eğer ⌘ command tuşunu kullanmazsak sürüklediğimiz referans kopyalanmış olacak (aslında yukarıdaki problemin aynısı).</blockquote><blockquote>Düzgün bir referansımız olduğu sürece geri kalan her şey aynı olmalı. Makalenin devamında iç içe eklenmiş projeleri göreceksiniz fakat hangi yolu kullanarak entegre ettiğinizden bağımsız, alacağınız sonuçlar aynı olacaktır.</blockquote><h4>Test sürüşüne çıkalım</h4><p>Her şey yolunda gidiyor. Bu noktaya kadar beni takip ettiyseniz proje düzeninizin aşağıdaki ekrandaki gibi olması gerekiyor. Şimdi framework’ümüzü uygulamamızda kullanma vakti! Taslak olarak gelen ViewController sınıfımızı açıyoruz ve aşağıdaki gibi düzenliyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*T2kX3qyttqKO7mFsacynMg.png" /></figure><p>Framework’ümüzü import ettik ve bu sınıfta kullanılabilir olmasını sağladık. Basitçe framework’ümüze eklediğimiz AwesomeAPIClient sınıfımızdaki testRun fonksiyonunu, viewDidLoad fonksiyonu içerisinde çağırıyoruz. Uygulamayı çalıştırın. Konsolda aşağıdaki çıktıyı görmemiz gerekiyor.</p><blockquote>AwesomeAPIClient is up and running! 🎉</blockquote><h4>Gereksinimler</h4><p>Veya ‘third party libraries’ 😄. İşimizi kolaylaştıran faydalı ve güzel (en azından bir çoğu güzel 🤪) kütüphaneler. Ve bunları projelerimize entegre etmemizi sağlayan iki popüler araç <a href="https://cocoapods.org/">CocoaPods</a> ve <a href="https://github.com/Carthage/Carthage">Carthage</a>. Her ikisinin de artıları ve eksileri, sevenleri sevmeyenleri var. Ben yıllardır CocoaPods kullandım, fakat özellikle son zamanlarda bu tür bir düzen ile Carthage kullanmaya başladım ve bence bu düzene de oldukça uyum sağlıyor.</p><p>Bu düzende bir çok framework’ümüz olabilir, sadece bir tane ile sınırlı değiliz. Uygulamalarımızdan bir çok yeniden kullanılabilir parçaları, özellikle API çağrılarını yaptığımız istemcileri, UI elemanlarını, veri saklama katmanlarını, Swift eklentilerini ve daha bir çok kendi başına kullanılabilir birimleri kendi framework’lerine ayırabiliriz. Şöyle de düşünebilirsiniz, eğer projenizde mantıksal gruplama yapıyorsanız, her bir grubu kendi framework’üne ayırabilirsiniz. Bu sayede her birini kendi içerisinde test edebilir, başka projelerde de kullanabilirsiniz. Şimdi API çağrılarını yaptığım katmanı veya veri saklama katmanımı ayırsam diğer uygulamalarda nasıl kullanabilirim, bunlar zaten bu uygulamaya özel gibi düşünebilirsiniz. Fakat bunları genel amaçlı yapıp uygulamanızda da özelleştirebilirsiniz. Mesela genel amaçlı bir veri saklama katmanınız olur, hatta bu katman kendisi de başka framework’ler kullanabilir (örneğin Core Data veya Realm), ve uygulama tarafında bu katmanın içerisinde bulunduğu framework’ü kullanabilirsiniz.</p><p>Peki Carthage bu düzene nasıl uyum sağlıyor? Workspace’inizde birden fazla proje olduğunu düşünün. Bu projelerden ikisinin aynı framework’e ihtiyaç duyduğu bir durumda olabilirsiniz. Carthage projelerimize ve workspace’imize ellemeyip bize projelerimize ekleyebileceğimiz bir framework verdiği için, birden fazla projeye ve ürüne ekleme şansımız oluyor. Fakat CocoaPods girdi olarak bir Xcode projesi alıp, çıktı olarak içerisinde bizim projemizin ve kendi Pods projesinin olduğu bir workspace verdiği için bizim oluşturduğumuz şekilde bir düzen oluşturmak mümkün olmuyor (CocoaPods kullanımına veya detaylarına dair bir şey gözden kaçırmıyorsam). Fakat CocoaPods’a işimizi gördürsek dahi birden fazla proje için birden fazla Podfile ile uğraşmak mantıklı değil.</p><p>Lafı daha fazla uzatmadan hadi bir kaç framework indirelim. AwesomeAPI framework’ümüz bizim için API isteklerini yapacağı için bir başka mükemmel framework olan <a href="https://github.com/Alamofire/Alamofire/">Alamofire</a>’ı eklemezsek olmaz!</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*uXh7OCFy3PKu_k5lfXq3bA.png" /></figure><p>Çalışma ortamımızı düzenli tutmak için, Vendor adında ayrı bir dizin oluşturup Carthage kullanımımızı bu dizin içine sınırlamamız iyi bir fikir olacaktır. Bu dizin içerisinde Cartfile adında bir dosya oluşturuyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*cmwhyiFuUITthCVvkOAnKg.png" /></figure><p><a href="https://github.com/Carthage/Carthage#adding-frameworks-to-an-application">Carthage dokümantasyonuna</a> göre carthage update komutunu yine aynı dizin içerisinde çalıştırmamız gerekiyor. Eğer sadece iOS projeniz var ve hem zamandan hem de disk yerinden tasarruf etmek istiyorsanız, Carthage’a sadece iOS için framework derlemesini komutumuza --platform ios parametresini ekleyerek belirtebiliriz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*K5QCaZSKrSwBi9xCi2WWeg.png" /></figure><p>Vendor/Carthage/Build/iOS dizininde yeni derlenmiş, taze Alamofire.framework. Bu framework’ü basitçe projemize sürükle-bırak yaparak ekleyebiliriz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*qXV6CJLJZ2aaVDRgfRelzw.png" /></figure><p>Proje altında Frameworks adında bir grup oluşturdum ve Alamofire.framework’ü buraya sürükle-bırak yaptım ve yukarıdaki ekranı görüyorum. Yine Copy items if needed seçeneğinin <strong>seçili olmadığına</strong> emin olun. Bu sayede biz framework’ü güncellesek dahi projemiz aynı framework’ü referans edecek. Finish diyin ve framework’ün Linked Frameworks and Libraries bölümüne de eklendiğini göreceksiniz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*8KWmgSheldYPovXrQfmLEQ.png" /></figure><h4>Test sürüşümüzü bir sonraki seviyeye çıkaralım</h4><p>AwesomeAPIClient sınıfımızda Alamofire framework’ünü dahil edelim ve testRun fonksiyonumuza örnek bir istek ekleyelim.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*B47uTFDkotjwpPaSuQcS5w.png" /></figure><blockquote>No such module ‘Alamofire’</blockquote><p>Bu hata ne şimdi? Zaten framework’ü eklemiştik. Modülü neden bulamıyor? Bunun sebebi, Xcode framework’ün nerede olduğunu bilmemesi. Nerede olduğunu derken diskteki yerini kasdediyoruz. Bu hatayı gidermek için, soldaki panelden projemizi seçiyoruz. Targets kısmında framework’ümüz seçili iken Build Settings sekmesine geliyoruz. Arama kısmına ‘Framework search paths` yazarak düzenleyeceğimiz girdiyi buluyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*-8CwDPQh85NVFxJ-_HAmsg.png" /></figure><p>Bu girdide Xcode’a projemizin kulladığı framework’leri aramasını istediğimiz dizini belirtiyoruz. Birden fazla dizin belirtebiliyoruz. Ayrıca çeşitli konfigürasyonlar (Debug, Release gibi) için farklı dizinler de belirtebiliyoruz. Fakat biz hepsi için aynı dizini belirtmek istediğimiz için girdiye çift tıklayarak Carthage’ın framework’ümüzü sakladığı dizinin yolunu giriyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*QBFG2SgUjG3Asg81W75f5w.png" /></figure><p>PROJECT_DIR değişkeni AwesomeAPI projemizin içerisinde olduğunu dizinin yolunu saklıyor. Bu Xcode’un önceden tanımladığı değişkenlerden biri sadece. Bu ve diğer değişkenler hakkında daha fazla bilgiye <a href="https://help.apple.com/xcode/mac/9.3/#/itcaec37c2a6">şuradan</a> ulaşabilirsiniz.</p><p>Bu ayarımızı da yaptıktan sonra AwesomeAPI şemamızı seçip derleyelim ve her şeyin yolunda olduğundan emin olalım.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*nw0DUyrbV-ts-f3fUCYXuQ.png" /></figure><p>Şimdi testRun fonksiyonumuza örnek isteğimizi ekleyelim.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*IxlBgIdtvSJHrbx0Vuvh9g.png" /></figure><p>Bu örneği <a href="https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#making-a-request">Alamofire dokümantasyonundan</a> aldım. Basitçe isteği gönderdiğimizden ve geçerli bir yanıt aldığımızdan emin olmak için bir birim testi ekleyebiliriz. Sonuçta hepimiz kodunu test eden iyi yazılımcılarız değil mi? DEĞİL Mİ? 👀</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*bXCHZo5HVOcceqmvJ8W5_Q.png" /></figure><p>Burada çok basit bir test ekledik. Fakat bu noktada yapmamız gereken bir şey daha var. Testlerimizi çalıştıran birim aslında framework’ümüzden ayrı bir ürün (AwesomeAPITests). O yüzden Alamofire framework’ünü de bu ürüne eklememiz gerekiyor. Bütün bu işler çetrefilli gelebilir ama inanın değil. Kısa sürede bu adımları kavrayıp mantığını çözerseniz gözünüz kapalı yapar hale gelirsiniz. Ve genelde bütün bu kurulumu bir proje için en fazla bir kere yapacaksınız. Sonrasında getirdiği avantajlar bütün bu zaman ve efor yatırımınıza değmiş olacak.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*8M-rprGfpq6EsTB2a9FSNg.png" /></figure><p>Yine sol panelden projemizi seçiyoruz. Bu sefer Targets kısmından test ürünümüzü seçiyoruz. Build Phases sekmesinde, sol üstteki +’ya basıyoruz ve açılan menüden New Copy Files Phase seçiyoruz. Bu önümüzdeki listeye yeni bir girdi ekliyor. Yeni girdinin adını burada benim yaptığım gibi Copy Frameworks olarak değiştirebilirsiniz. Sonuçta yapacağı iş sadece framework kopyalamak olacak. Destination kısmından Frameworks seçiyoruz ve listenin altındaki +’ya basarak Alamofire.framework’ü ekliyoruz. Şimdi AwesomeAPI şeması seçili iken ⌘+U ile testleri çalıştırın ve testlerin başarılı sonuçlandığını görün.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*UksZ2MBAnmzNsQQsbATPGA.png" /></figure><p>Voila!</p><h4>Süper! Hadi uygulamada da kullanalım</h4><p>ViewController sınıfımızı açın ve hemen bir hata göreceksiniz. Görmediyseniz de ilk derleme girişiminizde göreceksiniz. 😅</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*ewFkqH87IwFLkQP_jhmSmA.png" /></figure><p>Bunun sebebi açık. testRun fonksiyonumuzu güncellemiştik fakat değişiklikleri buraya yansıtmadık.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*jCUMbf9aqJVvsblGn2XfSg.png" /></figure><p>Bu demoyu karmaşık bir hale getirmemek için testRun fonksiyonumuzda herhangi bir veri veya hata parametresi eklemedik. testRun fonksiyonu zaten print çağrılarına sahip. O yüzden bu fonksiyonu uygulamamız çağırdığı zaman isteğimiz başarılı olursa konsolda çıktıları yine göreceğiz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*KwiJGtTAtmcAC6DWxyweKw.png" /></figure><p>Fakat uygulamamızı çalıştırır çalıştırmaz bir hata ile karşılaşıyoruz.</p><blockquote>dyld: Library not loaded: @rpath/Alamofire.framework/Alamofire<br> Referenced from: /Users/ilter/Library/Developer/Xcode/DerivedData/MultiProject-attxtmjkzrjkqibyrvrfpwmyfhby/Build/Products/Debug-iphonesimulator/AwesomeAPI.framework/AwesomeAPI<br> Reason: image not found</blockquote><p>Ama neden? Bütün kurulumları yapmıştık. Hata Alamofire framework’ünü bulamadığını söylüyor fakat AwesomeAPI framework’ümüz zaten kullanıyor onu. Sıkıntı ne ki şimdi?</p><p>Aslında cevabı zaten verdik. AwesomeAPI framework’ümüz Alamofire framework’ünü <strong>kullanıyor</strong>. Alamofire framework’ünü AwesomeAPI framework’üne bağlama işlemini yapmıştık ve AwesomeAPI framework’ünün de uygulamamıza gömülü olmasını ayarlamıştık. Fakat AwesomeAPI framework’ünü gömülü olacak şekilde ayarlamamız Alamofire framework’ünün de gömülü olacağı anlamına gelmiyor. Herhangi bir framework bir başka framework’ü kullanıyorsa, kullandığı framework’ü beraberinde getirme veya kendi içeriğine dahil etme gibi bir işlem yapmıyor. Ve Alamofire framework’ü iOS işletim sistemi bünyesinde bulunan bir framework olmadığı için, ayrıca onun da uygulamamıza gömülü olmasını sağlamamız gerek. İşlemin sonunda aslında aşağıdaki gibi bir düzen elde edeceğiz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Pc_5FNE12PiC_ohmrvdf6Q.png" /></figure><p>Özetle AwesomeAPI ve Alamofire framework’lerini uygulamamız içerisinde gömülü yapacağız. Herhangi bir framework bir başka framework’ü kendi içerisine gömülü yapamadığı için, uygulamamızın ikisini de beraberinde getirmesini sağlayacağız.</p><p>AwesomeAPI framework’ünü çok kolay entegre etmiştik fakat Alamofire için biraz farklı bir işlem yapacağız. Buradaki detay şu, Alamofire framework’ünü indirip derlemek için Carthage kullanmıştık. Ve şu an Alamofire framework’ü bizim kullandığımız veya kullanmadığımız birden fazla mimariye destek veriyor. Bunlar çeşitli iOS cihazları (arm64, armv7 ve armv7s) ve iOS Simulator (i386). Framework içerisinde desteklenen her bir mimari için ayrıca derlenmiş bir birim bulunuyor (İngilizce adı ‘slice’). Bunların hepsini uygulamamıza dahil etmemizde kesinlikle hiçbir sıkıntı yok. Uygulamamız beklediğimiz şekilde çalışacaktır. Sadece herhangi bir iOS cihazında kullanamayacağımız ekstra bir mimari (i386) için de bir parça bulundurmuş olacağız. Fakat bu hamle uygulamamızı App Store’a gönderirken bir sıkıntıya sebep olacak. iTunes Connect desteklenmeyen mimariler için bulundurduğumuz parçaları çıkarmamızı isteyecek. Bu noktada yine Carthage bize yardım edecek.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*NyRS-RuMWNSLvtv9xnTqcg.png" /></figure><p>AwesomeAPI framework’ümüzün test ürünü için yaptığımız gibi uygulamamız için de ‘Build Phases’ sekmesinde yeni bir girdi oluşturuyoruz. Bunun için sol üstteki +’ya basıp Run Script Phase seçiyoruz. Yine adını amacına uygun olmasını istediğim için Carthage (Copy Frameworks) olarak değiştirdim. Burada Carthage kullanarak gerekli mimarilerin desteğinin uygulamamıza eklenmesini sağlıyoruz. Girdi listesinde Alamofire.framework’ünün yolunu giriyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*0dIpN9o1O6sy3FbT6KGn5g.png" /></figure><p>Ve çıktı listesine de framework’ün kopyalanması gereken uygulamanın içerisindeki Frameworks dizininin yolunu giriyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*O4Xh0sFJoidZGXlO7QwXig.png" /></figure><blockquote>Yukarıda gösterdiğim Alamofire.framework’ün bulunduğu dizin benim bilgisayarımda şu şekilde:<br> ~/Library/Developer/Xcode/DerivedData/MultiProject-attxtmjkzrjkqibyrvrfpwmyfhby/Build/Products/Debug-iphonesimulator/TheNextBigThingApp.app/Frameworks/Alamofire.framework<br> Framework’ün kopyalanması için bu ayarı yaptıktan sonra uygulamayı bir kere derleyerek yukarıdaki dizine kopyalandığını görebilirsiniz.</blockquote><blockquote>$SRCROOT, $BUILT_PRODUCTS_DIR ve $FRAMEWORKS_FOLDER_PATH Xcode tarafıdan tanımlanmış diğer değişkenler.</blockquote><p>Şimdi uygulamamızı çalıştıralım.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*YdbYfPXLgwF59WVWlIvjhw.png" /></figure><p>Voila! İşte beklediğimiz konsol çıktısı!</p><h4>Sonuç</h4><p>Şimdiye kadar yaptıklarımızı ufak bir listede derlemek istersek:</p><ul><li>Boş bir Xcode workspace oluşturduk</li><li>iOS uygulamamız için bir proje oluşturduk ve bunu workspace’imize ekledik</li><li>Framework’ümüz için de bir proje oluşturduk ve bunu da workspace’imize ekledik</li><li>Yeni oluşturduğumuz framework’ümüzü uygulamamıza bağladık ve gömülü olmasını ayarladık</li><li>Carthage ile Alamofire framework’ünü indirip derledik</li><li>Alamofire framework’ünü kendi framework’ümüze bağlayıp kullandık</li><li>Alamofire framework’ünün uygulamamıza gömülü olmasını ayarladık</li></ul><p>Bu şekilde istediğiniz kadar birbirinden ayrı projeler oluşturabilirsiniz ve bunların birbirini veya uygulamanızın hepsini kullanmasını sağlayabilirsiniz. Alamofire gibi birçok harici framework ekleyebilirsiniz. Bu harici framework’leri bir veya daha fazla framework’ünüz veya uygulamanız kullanabilir. Yani istediğiniz çeşitlilikte bir düzen oluşturabilirsiniz.</p><p>Kendi oluşturduğunuz framework’lerinizi diğer projelerinizde de kullanabilirsiniz. Hatta kendi framework’ünüz için ayrı bir depo oluşturup, Carthage veya git submodules kullanarak diğer projelerinizin workspace’lerine ekleyebilirsiniz. Carthage ile kendi framework’lerinizi eklerseniz, framework’leriniz hali hazırda derlemiş olacağı için uygulamanızın testleriniz esnasında daha kısa sürede derlenmesini de sağlayabilirsiniz. Birden fazla projemizin olmasının bir diğer avantajı ise herhangi bir birimde yaptığımız değişiklik için projemizin bütün testlerini çalıştırmamız gerekmiyor. Her birimin kendi testleri ayrı ayrı çalıştırılabilir halde oluyor. Bu şekilde bir düzen oldukça esneklik sağlıyor ve bir çok getirisi var.</p><p>Yazı boyunca oluşturduğum örnek projeyi <a href="https://github.com/iltercengiz/MultiProject">burada</a> bulabilirsiniz.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4b410226635f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/nsistanbul/xcode-workspace-ile-birden-fazla-proje-kurulumu-4b410226635f">Xcode Workspace ile Birden Fazla Proje Kurulumu</a> was originally published in <a href="https://medium.com/nsistanbul">NSIstanbul</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Multi Project Setups]]></title>
            <link>https://medium.com/objective-tidbits/multi-project-setups-fee9d235d857?source=rss-ef4293c548f5------2</link>
            <guid isPermaLink="false">https://medium.com/p/fee9d235d857</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[workspace]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[framework]]></category>
            <category><![CDATA[dependencies]]></category>
            <dc:creator><![CDATA[Ilter Cengiz]]></dc:creator>
            <pubDate>Sat, 12 May 2018 14:22:45 GMT</pubDate>
            <atom:updated>2020-02-21T11:02:30.473Z</atom:updated>
            <content:encoded><![CDATA[<p>This post is a tutorial to setup a multi project iOS application workspace. It doesn’t necessarily need to be an iOS application though, this setup can be used for macOS, tvOS, or a mixture of those platforms to share some of the code base.</p><p>So what’s the purpose?</p><ul><li>This approach will allow you to think in terms of modules. Separating your project into multiple modules will allow you to design better abstractions.</li><li>It will also help you to save time in testing, since every module will be treated as a separate product and they will all have their own set of tests.</li><li>Another benefit is the reusability. Every module can be reused in multiple projects. Saving us time in both during development and maintenance.</li></ul><p>Throughout this tutorial, we will be using Xcode 9.3. There’s a slight difference in multi project setups if you’re using Xcode 9.3 or an older version. I’ll be pointing the exact step when we get there.</p><p>Let’s get started!</p><h4>Workspace</h4><p>We will begin with an empty workspace. Create an empty Xcode workspace and place it in a directory of your choice.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*nZ7Va367OE_M0f7grbaitg.png" /></figure><p>So I’ve created a directory named MultiProject on my Desktop and created a workspace with the same name in that directory.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*aUx1-OEh3xdkG1XXNu7hLA.png" /></figure><p>And this is the workspace itself.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*6M4i9lmdx-Co8cGTDBRPdQ.png" /></figure><p>It has nothing. No project, no scheme, no files, nothing.</p><h4>Adding the application project</h4><p>Now let’s create the project for the app of the next big thing.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Jj_aqJatR1usbsJ3pncj-Q.png" /></figure><p>Again, we’re using the File menu of Xcode. When we select Project, we will be greeted with this screen.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*LrBlLmWwBRWVoQPfPMPLlw.png" /></figure><p>The window in the background is not our workspace but we will get there in a moment. Let’s stick with the basics and select Single View App. In the next screen fill in the details for the app and continue to the screen where we choose the directory for our project.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*_NKYG9iWW02uMrUHzj8cCQ.png" /></figure><p>Here’s the part that we add this project to our empty workspace. Instead of creating the project in another directory, just open Add to drop-down menu and select our workspace. As a side note, for the workspace to show up in this menu, it must be already open.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*TktjLgd9hvyWofhXi9AoSA.png" /></figure><p>And the moment we select our workspace, both the directory for the new project it’s showing becomes the directory that our workspace is in and also the Group drop-down menu shows our workspace meaning the new project will be placed in the root of our workspace. Just click Create and you will see the project being closed but instead is opened in the workspace.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*lanNgpzDRWMtC8evJkzvYA.png" /></figure><p>If we take a look at what we have right now, we have a workspace which has a project which has a target for the iOS app, a target for unit tests, and another target for UI tests. As we created the project in the workspace, the scheme for the app is also added as an option. This looks exactly as if we created a project and opened it.</p><h4>Adding the framework project</h4><p>Let’s make this look more like a workspace by adding another project. We will follow the same steps as we added the app project, but this time we will add a framework instead.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*2IQ_1KSeaW6P9L5fWWX69A.png" /></figure><p>On project creating step, make sure to select our workspace in both Add to and Group drop-down menus.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Way-chncBx_qPSEAPwR4RA.png" /></figure><p>This will place the directories for both the app and the framework side by side in the root directory. After clicking Create now we have this.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*8qiQbp2OOa2il35qgYXMFg.png" /></figure><p>Now this looks like a workspace. 😄</p><h4>Framework test run</h4><p>So far so good! Let’s create a new class for our lovely AwesomeAPI framework to use in the app target.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*xdwI2_9Eh0elDyJeF-oTnA.png" /></figure><p>Here we have a class named AwesomeAPIClient which is a singleton object and has a function named testRun. Notice how each component is declared public. Since this class will be available in AwesomeAPI framework, we need to declare every component that we want to access from the app target public.</p><h4>Linking the framework to the app</h4><p>Onto the app side. Let’s use the awesome framework in our app!</p><p>First we need to link the framework to the app target. But also we need to embed it to the app target as well, so that it will be bundled within the app when we build the app, making it available to use as if it’s a system provided framework.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*emLG69PUq4SLsHmBbuQ0eg.png" /></figure><p>On the project overview screen, just press the + button in Embedded Binaries section to show the above sheet. From there, select AwesomeAPI.framework and since the reason for embedding a framework is so obvious, Xcode will add it to the Linked Frameworks and Libraries section as well.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*corF30ZotLNDp1GGnHXyKg.png" /></figure><p>Notice the framework added to the project group in Project navigator. Before Xcode 9.3, we had to add a reference to the AwesomeAPI project <em>inside</em> the app project to make it visible to be linked and embedded. Now, Xcode 9.3 uses a different project and workspace structure (see the Project Format listing in File inspector on the right pane) that allows us to use other targets in other projects within the same workspace.</p><p>Unfortunately, Xcode doesn’t give us all the goodies at once. ¯\_(ツ)_/¯ This leaves us with a dangling framework inside the project group and the down side is, you can’t just move it to another group. You can try creating a New Group without Folder and moving the framework to it. It’ll just create another reference which is useless (it’s not the same reference that’s linked and embedded even).</p><p>If you’re living an <a href="https://en.wikipedia.org/wiki/Obsessive%E2%80%93compulsive_disorder">OCD</a>-free life, you might be like <em>‘okay, whatever’</em> with this kind of a structure. Another way is the old-fashioned-way I mentioned above. We’ll do the things as we would do with previous versions of Xcode. First, right-click and remove the framework from the app group. This will also remove it from Embedded Binaries and Linked Frameworks and Libraries section as well. Second, just create a group without a folder (preferably with the name Vendor) inside the app project group and drag-and-drop the AwesomeAPI project in it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*gDzK1Z5IpvnlxEthvtQepA.png" /></figure><p>Make sure to have the Copy items if needed <strong>unchecked</strong>. And finally, to link the framework, click the same + button in Embedded Binaries section to show the framework selection sheet.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*W4xB27ftUzNgwqSEXuEMWg.png" /></figure><p>Pay attention to the list above, we have two listing of the same framework. Make sure to choose the one within the app project group. This way we won’t have any additional framework references.</p><blockquote>17.05.2019</blockquote><blockquote><strong>Xcode 10.2.1 Update</strong></blockquote><blockquote>I’m not sure exactly when the aforementioned issue has been resolved but as I recently tried with Xcode 10.2.1, we don’t have to have a nested project anymore. And it’s also easier to maintain the project structure too.</blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*u0ZpXYFP5i5H_3ZwZIRWiw.png" /><figcaption>Framework is added to a group in the consumer project</figcaption></figure><blockquote>In the above screenshot, notice that Vendor group is empty, meaning that nested project is removed. Also I have a reference to AwesomeAPI.framework within the app’s project. Following the same steps above, after adding the framework, we can drag and drop the framework under any group <strong>while holding down the ⌘ command key</strong>. This bit is important, because if we don’t use the ⌘ command key, it’ll copy the reference (basically same problem above).</blockquote><blockquote>After having a proper reference, the rest basically the same. So you’ll see the nested project in the rest of the article, but regardless which way you consume the framework, result will be the same.</blockquote><h4>Run the test run</h4><p>All is well! Let’s use our framework in the app! Open the template ViewController class and modify it as follows:</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*T2kX3qyttqKO7mFsacynMg.png" /></figure><p>We imported our framework and called the testRun function on AwesomeAPIClient singleton in viewDidLoad function. Let’s run the app and we should see the following output in the console:</p><blockquote>AwesomeAPIClient is up and running! 🎉</blockquote><h4>Dependencies</h4><p>Dependencies are awesome! (Okay, at least most of it. 😅) And we have two <em>popular</em> options to integrate them to our projects. <a href="https://cocoapods.org/">CocoaPods</a> and <a href="https://github.com/Carthage/Carthage">Carthage</a>. Both of them have their pros and cons, lovers and haters. I have been using CocoaPods for years, but recently, especially with this setup, I have started to use Carthage and I think it fits very well for our case too.</p><p>With this kind of a setup, we can have many frameworks. Frameworks containing several reusable parts and layers of our application. Networking, UI components, persistence, analytics, extensions that we implement the extra stuff that should be already implemented in the language itself, and many more. In other words, the groups that you have in your application project. Each one of them can be a separate framework letting you reuse them in another project. Now you may think how can you reuse a networking layer or analytics logic that are so specific to your app. Well, at least you can have them contain the base implementations. For example you can make the networking framework free from any API URLs and make the app utilize it.</p><p>Why Carthage fits well with this setup? Imagine having many projects in our workspace. And two of them may need the same dependency. With Carthage, we can have this dependency be built in the root directory of our workspace and simply link it with both of the projects. But since CocoaPods takes a single project as an input and manipulates the project and adds it into a new workspace, it’s simply not possible for this setup (unless I’m missing some usage tips). Even if we could utilize CocoaPods, it just doesn’t make sense to maintain two or more separate Podfiles for a given dependency.</p><p>Without further ado, let’s setup our dependencies. Since AwesomeAPI is our gate to the interwebs, it’s a high probability for us to use another awesome framework, <a href="https://github.com/Alamofire/Alamofire/">Alamofire</a>!</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*uXh7OCFy3PKu_k5lfXq3bA.png" /></figure><p>To keep things tidy, it’s a good idea to keep all of our Carthage setup in a separate directory, Vendor. Inside this directory, let’s create a Cartfile.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*cmwhyiFuUITthCVvkOAnKg.png" /></figure><p><a href="https://github.com/Carthage/Carthage#adding-frameworks-to-an-application">As per the documentation of Carthage</a> we need to run carthage update in the same directory. If you want to limit framework builds for only iOS we need to add --platform ios parameter to this command.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*K5QCaZSKrSwBi9xCi2WWeg.png" /></figure><p>In Vendor/Carthage/Build/iOS directory, rests our lovely Alamofire.framework which we can simply drag-and-drop to our project.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*qXV6CJLJZ2aaVDRgfRelzw.png" /></figure><p>Again I created a new group without folder reference named Frameworks and dragged-and-dropped the Alamofire.framework in this group which led me to the above screen. Also again, make sure to have the Copy items if needed option <strong>unchecked</strong>. This will allow us to reference the same framework whenever we update it with Carthage. Click Finish and notice the framework is already added in Linked Frameworks and Libraries section.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*8KWmgSheldYPovXrQfmLEQ.png" /></figure><h4>Up the game with test run</h4><p>Let’s import Alamofire in AwesomeAPIClient class to make a sample request in testRun function.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*B47uTFDkotjwpPaSuQcS5w.png" /></figure><blockquote>No such module ‘Alamofire’</blockquote><p>What’s this about? We already linked the framework. Why can’t it find the module? That’s because Xcode doesn’t know where to find the framework. To fix this, select the project from Project navigator and while the framework target is selected navigate to Build Settings tab. In the search bar type ‘Framework search paths’.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*-8CwDPQh85NVFxJ-_HAmsg.png" /></figure><p>This is the field that we need to tell the directories our frameworks reside to Xcode. Since we need the same information for every configuration we have (Debug, Release, etc.), just double click and enter the Carthage iOS build directory path.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*QBFG2SgUjG3Asg81W75f5w.png" /></figure><p>PROJECT_DIR variable points to the directory AwesomeAPI project is in. For more information about build settings and available variables, please refer <a href="https://help.apple.com/xcode/mac/9.3/#/itcaec37c2a6">here</a>.</p><p>With the path set, select the AwesomeAPI framework scheme and confirm that it builds successfully.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*nw0DUyrbV-ts-f3fUCYXuQ.png" /></figure><p>Let’s add a request to testRun function.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*IxlBgIdtvSJHrbx0Vuvh9g.png" /></figure><p>I just took this sample from the <a href="https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md#making-a-request">Alamofire documentation</a>. To make sure the request is being sent and we get a valid response, we can add a simple test case for this class. In the end, we are all good developers who write tests, right? RIGHT? 👀</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*bXCHZo5HVOcceqmvJ8W5_Q.png" /></figure><p>Here’s a very basic test. But we need one more thing to do. Since test target is a separate build than our framework, we need to make sure it’s embedding Alamofire.framework as well. You may think that these are all very cumbersome when using Carthage but trust me it’s not. You just need to get a grasp of it and you will be doing all this setup at most once per project. After that, all is well!</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*8M-rprGfpq6EsTB2a9FSNg.png" /></figure><p>Select the project from Project navigator and while the test target is selected navigate to Build Phases. Here, click the + button on the top left corner and select New Copy Files Phase. This will add a new entry. You can rename it from Copy Files to Copy Frameworks as I did above, since it will be responsible for framework copy task only. Choose Frameworks from the Destination drop down menu and using the + button under the list, add Alamofire.framework. Hit ⌘+U while AwesomeAPI scheme is selected and watch as your test succeeds.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*UksZ2MBAnmzNsQQsbATPGA.png" /></figure><p>Voila!</p><h4>Perfect! Let’s use it in the app as well</h4><p>Open ViewController class and you should see an error immediately (or at least when you try to build the app).</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*ewFkqH87IwFLkQP_jhmSmA.png" /></figure><p>This is obviously because we modified testRun function. Let’s reflect the changes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*jCUMbf9aqJVvsblGn2XfSg.png" /></figure><p>For the sake of this tutorial, we there’s not any data passed in, but testRun function has still print statements in place. So when the network request succeeds we should see the result printed in the console.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*KwiJGtTAtmcAC6DWxyweKw.png" /></figure><p>But instead we get an immediate crash.</p><blockquote>dyld: Library not loaded: @rpath/Alamofire.framework/Alamofire<br> Referenced from: /Users/ilter/Library/Developer/Xcode/DerivedData/MultiProject-attxtmjkzrjkqibyrvrfpwmyfhby/Build/Products/Debug-iphonesimulator/AwesomeAPI.framework/AwesomeAPI<br> Reason: image not found</blockquote><p>But why? We are using Alamofire in our AwesomeAPI framework already? What’s wrong here?</p><p>The answer is, AwesomeAPI framework <strong>uses</strong> Alamofire framework. We linked Alamofire framework to AwesomeAPI framework and AwesomeAPI framework is both linked and <strong>embedded</strong> to our app target. But embedding a framework to an app target does <strong>not</strong> bring the other frameworks that are linked to the embedded framework along with itself. Since Alamofire is not a framework that ships with iOS, we need to embed it to our app target too. In the end we will have a setup as follows.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Pc_5FNE12PiC_ohmrvdf6Q.png" /></figure><p>So basically AwesomeAPI and Alamofire frameworks both will be the dependencies that we ship with our app. Frameworks can’t embed any other framework but since our app target is capable of embedding frameworks, we need to embed Alamofire too, even though we’re not directly using it.</p><p>To embed Alamofire we’re going to do something slightly different from what we did while embedding it into AwesomeAPITests target. The detail here is, as we have used Carthage to download and build Alamofire framework, it contains all the binary slices which includes iOS (arm64, armv7, and armv7s) and iOS Simulator (i386). It’s totally okay to have all slices in the framework shipped with the app, it will work. But you will see an error from iTunes Connect when you try to upload your app to the App Store. It will warn you to remove unused slices (in this case, i386 architecture slice, since none of the simulators will download our app from the App Store). Carthage is ready to help us with that.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*NyRS-RuMWNSLvtv9xnTqcg.png" /></figure><p>Switch to Build Phases tab in the app’s project and add another Run Script Phase. I renamed it to Carthage (Copy Frameworks). Here we’re using Carthage to copy the frameworks which is only copying the necessary slices. As input we’re pointing to Alamofire.framework in our Carthage build directory.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*0dIpN9o1O6sy3FbT6KGn5g.png" /></figure><p>And as the output we’re pointing to the Frameworks directory inside the application bundle.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*O4Xh0sFJoidZGXlO7QwXig.png" /></figure><blockquote>The path to Alamofire.framework shown above is<br> ~/Library/Developer/Xcode/DerivedData/MultiProject-attxtmjkzrjkqibyrvrfpwmyfhby/Build/Products/Debug-iphonesimulator/TheNextBigThingApp.app/Frameworks/Alamofire.framework<br> You can find the framework in its place after building the app once more.</blockquote><blockquote>$SRCROOT, $BUILT_PRODUCTS_DIR, and $FRAMEWORKS_FOLDER_PATH are all predefined variables in the environment added by Xcode.</blockquote><p>Let’s build and run now.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*YdbYfPXLgwF59WVWlIvjhw.png" /></figure><p>Voila! As we see the expected console output, all is well.</p><h4>Conclusion</h4><p>To sum up what we have done until now:</p><ul><li>Created an empty Xcode workspace</li><li>Created an Xcode project for our iOS app and added it to the workspace</li><li>Created an Xcode project for our framework and added it to the workspace too</li><li>Linked and embedded the framework to the iOS app and used it in the view controller</li><li>Added a dependency with Carthage</li><li>Linked the dependency to the framework</li><li>Embedded the dependency to the iOS app using Carthage</li></ul><p>You can have as many separate projects as you like and all of them can be consumed by your app target. You can have as many dependencies as you want and multiple projects can easily consume them too. Your dependencies not necessarily need to be linked to a framework. You can have one or more dependencies consumed by both frameworks and app targets. You can mix and match however it fits your needs.</p><p>You can even use your own frameworks in other projects too. For example you can have a separate repo for a framework and add it to many workspaces and repos either using Carthage or git submodules. And if you add frameworks prebuilt with Carthage you can shorten the build times for the app as well. It’s also helpful in terms of tests. You don’t need to run all of the test suite just for a change in one of the frameworks or the apps. This setup is very flexible and provides many benefits.</p><p>You can find the sample repo <a href="https://github.com/iltercengiz/MultiProject">here</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fee9d235d857" width="1" height="1" alt=""><hr><p><a href="https://medium.com/objective-tidbits/multi-project-setups-fee9d235d857">Multi Project Setups</a> was originally published in <a href="https://medium.com/objective-tidbits">Objective Tidbits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The not-so-obvious UISplitViewController warning]]></title>
            <link>https://medium.com/objective-tidbits/the-not-so-obvious-uisplitviewcontroller-warning-ab3ac77d0887?source=rss-ef4293c548f5------2</link>
            <guid isPermaLink="false">https://medium.com/p/ab3ac77d0887</guid>
            <category><![CDATA[uisplitviewcontroller]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Ilter Cengiz]]></dc:creator>
            <pubDate>Thu, 05 Apr 2018 20:30:38 GMT</pubDate>
            <atom:updated>2018-04-05T20:30:57.349Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xggD1iDWR8iqu5gq26zJ0Q.png" /></figure><p>If you’re using UISplitViewController in your app and mostly (if not completely) building your view controller hierarchy in code instead of adding view controllers to it in storyboard, you may have seen this warning:</p><pre><strong>[Warning] Splitview controller &lt;UISplitViewControllerClassicImpl: 0x7fd5fae07c00&gt; is expected to have a view controller at index 0 before it&#39;s used!</strong></pre><p>At first I didn’t pay attention to this warning as my app was already working as I expected. But then, as always, it just annoyed me. After a quick research what would be causing this I came across to <a href="https://stackoverflow.com/a/18046280/1931781">this StackOverflow answer</a>.</p><p>So in my case I was doing the following:</p><pre>splitViewController.preferredDisplayMode = .allVisible<br>splitViewController.viewControllers = [...]</pre><p>Probably, setting the preferredDisplayMode is triggering the view to be loaded and since we don’t have any view controllers assigned, it’s just printing the above warning to the console.</p><p>The solution is simple. Just assign the view controllers first and later do whatever you need to do with split view controller. 😁</p><pre>splitViewController.viewControllers = [...]<br>splitViewController.preferredDisplayMode = .allVisible<br>// any further customizations</pre><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ab3ac77d0887" width="1" height="1" alt=""><hr><p><a href="https://medium.com/objective-tidbits/the-not-so-obvious-uisplitviewcontroller-warning-ab3ac77d0887">The not-so-obvious UISplitViewController warning</a> was originally published in <a href="https://medium.com/objective-tidbits">Objective Tidbits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Working with universal links on iOS simulator]]></title>
            <link>https://medium.com/objective-tidbits/working-with-universal-links-on-ios-simulator-adffb7767801?source=rss-ef4293c548f5------2</link>
            <guid isPermaLink="false">https://medium.com/p/adffb7767801</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[universal-links]]></category>
            <dc:creator><![CDATA[Ilter Cengiz]]></dc:creator>
            <pubDate>Thu, 08 Jun 2017 12:01:44 GMT</pubDate>
            <atom:updated>2018-07-23T15:03:30.867Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6fNwhXXWs61whik6." /><figcaption>Photo by <a href="https://unsplash.com/@kylejglenn?utm_source=medium&amp;utm_medium=referral">Kyle Glenn</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>We can use web URLs for opening content in an application for a while. The setup is very basic. Just write the domains you want to handle in you entitlements file and you’re good to go! (Focusing on the iOS side, skipped domain setup.) From now on, your users can open your application with your links to your domain.</p><p>Apart from opening the application we also need to handle the action. So you need to publish a URL like <a href="http://www.example.com/contents/3">www.example.com/contents/3</a> and when this URL is opened on the device, you expect the application to, as you can guess, open the content screen for the content whose id is 3.</p><p>Also I’m skipping how to handle this action, because it really depends on the setup and/or architecture of your application. I’m just going to focus on testing this feature, on iOS simulator.</p><p>We have to have the URL written somewhere on the device, be it an SMS message, an email, and/or a note. Since these are limited/not available on the iOS simulator, we need some other way to test universal links.</p><h3>xcrun to the rescue</h3><p><em>xcrun</em> supports opening URLs on iOS simulator as if they have been triggered by a user action.</p><blockquote>xcrun simctl openurl booted “https://www.example.com/content?id=2”</blockquote><p>URL can also be written without the quotes but if you have query parameters in it, it will simply fail. But if it’s a plain URL, like so:</p><blockquote>xcrun simctl openurl booted https://www.example.com/faq</blockquote><p>you are good to go. We can also use app schemes as well:</p><blockquote>xcrun simctl openurl booted “exampleapp://example/content?id=2”</blockquote><p>So if you’re having all your USB ports plugged in with other stuff like me, you can test universal links on iOS simulator using <em>xcrun</em>!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=adffb7767801" width="1" height="1" alt=""><hr><p><a href="https://medium.com/objective-tidbits/working-with-universal-links-on-ios-simulator-adffb7767801">Working with universal links on iOS simulator</a> was originally published in <a href="https://medium.com/objective-tidbits">Objective Tidbits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Alternative Button]]></title>
            <link>https://medium.com/objective-tidbits/alternative-button-4a7997b4ad7?source=rss-ef4293c548f5------2</link>
            <guid isPermaLink="false">https://medium.com/p/4a7997b4ad7</guid>
            <category><![CDATA[button]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Ilter Cengiz]]></dc:creator>
            <pubDate>Fri, 16 Dec 2016 05:10:29 GMT</pubDate>
            <atom:updated>2016-12-16T05:10:29.387Z</atom:updated>
            <content:encoded><![CDATA[<p>There must be a time when every iOS developer wanted to place the image of `UIButton` above the title. Alternative Button is here for that!</p><h4>TL;DR</h4><p>Alternative Button is available as a pod. You can easily add it to your project just by adding `pod ‘AlternativeButton’` to your ‘Podfile’ and running `pod install` in your project directory.</p><p>Also you can find both Alternative Button and the example project <a href="https://github.com/iltercengiz/AlternativeButton">here</a>.</p><h3>Structure</h3><p>Alternative Button is a subclass of `UIButton` and just by overriding a few methods and a few additions, it presents its image above the title. And thanks to a new feature of Xcode 6, it can be previewed in Interface Builder. Also corner radius of its image view can be set from Attributes Inspector too.</p><h3>Layout</h3><p>By overriding `-layoutSubviews` method of `UIView`, we can interfere with the view hierarchy and layout of any subview of a view. So we did:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/85896c27f4657fb7b7b047cde53fe9a8/href">https://medium.com/media/85896c27f4657fb7b7b047cde53fe9a8/href</a></iframe><blockquote>`imageViewWidth` is a constant defined in the class and its value is `64.0`</blockquote><p>Here we just adjust the frames of both image view and the title label. We place them vertically in line and horizontally centered.</p><h3>Size</h3><p>`-intrinsicContentSize` method of `UIView` returns a `CGSize` indicating the desired size of itself. So we must override this too, like so:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/dd47098f2f9459f7aa5e98006df6eb41/href">https://medium.com/media/dd47098f2f9459f7aa5e98006df6eb41/href</a></iframe><p>Here we first adjust the size of title label, because it can be any size depending on the title set for the button. Then we get the width of both image view and the title label adding margins to them from both sides. Again, we calculate the height of the button, adding margins from both top and bottom.</p><blockquote>`margin` is a constant too, defined in the class and its value is `6.0`</blockquote><p>We return a `CGSize` created with the width of either image view or title label, which of them is greater, and the calculated height.</p><p>`-intrinsicContentSize` provides a size value to be used in Interface Builder, so that whenever ‘Size to Fit Content’ is selected from the ‘Editor’ menu, it adjusts the button’s size according to this value.</p><h3>Radius</h3><p>We also have a public property named `imageViewRadius`. This is used to round the corners of the image view. By default corner radius is set to be half of the image view’s width, so that it will be a perfect circle.</p><h3>IB_DESIGNABLE &amp; IBInspectable</h3><p>These are the new keywords Xcode 6 introduced. Thanks to these we can see a preview of our custom coded view in Interface Builder!</p><p>`IB_DESIGNABLE` tells Interface Builder that this is a custom view and needs a preview. We add this keyword just before class declaration in our header file.</p><p>`IBInspectable` tells Interface Builder that the property with this keyword can be adjusted from the Attributes Inspector. We add this keyword just before the type of our property.</p><h3>Result</h3><p>Here is a screen shot of the example project:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/375/1*9c6iZlX2oS1X7TAz6NRF1A.png" /></figure><p>I used this button as a profile button in my current project and wanted to open it to the world! So that, other developers in need of a control like this can benefit.</p><p>Feel free to contribute and let me know what you think in the comments!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4a7997b4ad7" width="1" height="1" alt=""><hr><p><a href="https://medium.com/objective-tidbits/alternative-button-4a7997b4ad7">Alternative Button</a> was originally published in <a href="https://medium.com/objective-tidbits">Objective Tidbits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Editing Changed]]></title>
            <link>https://medium.com/objective-tidbits/editing-changed-6b6624fc06fd?source=rss-ef4293c548f5------2</link>
            <guid isPermaLink="false">https://medium.com/p/6b6624fc06fd</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[textfield]]></category>
            <dc:creator><![CDATA[Ilter Cengiz]]></dc:creator>
            <pubDate>Fri, 16 Dec 2016 05:01:39 GMT</pubDate>
            <atom:updated>2016-12-16T05:13:17.591Z</atom:updated>
            <content:encoded><![CDATA[<p>`UITextViewDelegate` has a very useful method: `-textViewDidChange:`. As the name implies, text view calls this method on its delegate whenever the text it is currently presenting is changed.</p><p>But, unlike `UITextViewDelegate`, `UITextFieldDelegate` doesn’t have such a method. Instead, it has a hidden gem that provides the same functionality.</p><h3>UIControlEventEditingChanged</h3><p>Meet our hero! You can either assign an `IBAction` for this event in Interface Builder or add a target and action in code.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gMRIwbpBmQlW5rJJsDGBhw.png" /></figure><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/cc94b4d9f047b27fa8cdeca85d7cbd1c/href">https://medium.com/media/cc94b4d9f047b27fa8cdeca85d7cbd1c/href</a></iframe><p>This way, whenever a change appears on text field, it will call the action method assigned for `UIControlEventEditingChanged` event.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6b6624fc06fd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/objective-tidbits/editing-changed-6b6624fc06fd">Editing Changed</a> was originally published in <a href="https://medium.com/objective-tidbits">Objective Tidbits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Date Formatter]]></title>
            <link>https://medium.com/objective-tidbits/date-formatter-993d12cdd2f3?source=rss-ef4293c548f5------2</link>
            <guid isPermaLink="false">https://medium.com/p/993d12cdd2f3</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[date-formatting]]></category>
            <dc:creator><![CDATA[Ilter Cengiz]]></dc:creator>
            <pubDate>Fri, 16 Dec 2016 05:00:15 GMT</pubDate>
            <atom:updated>2018-04-05T20:35:00.892Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*AX_EqI1dm09UbCE0." /><figcaption>Photo by <a href="https://unsplash.com/@charlesdeluvio?utm_source=medium&amp;utm_medium=referral">Charles Deluvio 🇵🇭🇨🇦</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>One of the strongest classes of the Foundation framework undoubtly is `NSDateFormatter`. With `NSDateFormatter`, one can easily convert a date object into strings with various formats that human can read.</p><h3>NSDate</h3><p>`NSDate` is the class from Foundation framework that is used to represent dates. `NSDateFormatter` and `NSDate` objects are in cooperation for us humans to understand the dates.</p><p>To create a date object that contains current date and time simply create an `NSDate` object. In Objective-C:</p><pre>NSDate *currentDate = [NSDate date];</pre><p>And in Swift:</p><pre>let currentDate = NSDate()</pre><p>There are a few more ways to create date objects using time intervals. Time intervals are simply seconds. Also `NSTimeInterval`is simply a `typedef`ed `double`.</p><p>There are four initializer methods defined in `NSDate` which takes a time interval as a parameter. One of them is:</p><pre>let date = NSDate(timeIntervalSince1970:1426003200)</pre><p>You can have a look at its discussion and other forms in the documentation.</p><h3>NSDateFormatter</h3><p>Date formatters are expensive objects. It’s suggested to create them once and use the same formatter object for repeated tasks.</p><p>Simply create a date formatter object:</p><pre>let dateFormatter = NSDateFormatter()</pre><p>and set its date formatting style:</p><pre>dateFormatter.dateStyle = .MediumStyle</pre><p>Then give it a date object to format it:</p><pre>dateFormatter.stringFromDate(date)</pre><p>You’ll get the following output:</p><pre>“Mar 10, 2015”</pre><p>There are a few more predefined formats like `.MediumStyle`. They are `NoStyle`, `ShortStyle`, `LongStyle`, and `FullStyle`. Try them out!</p><h3>Custom Formats</h3><p>You can also define your own formats. Just provide `NSDateFormatter` a format string and the rest is the same procedure.</p><pre>dateFormatter.dateFormat = “HH:mm, d MMM yyyy”</pre><p>With this format, you can get a string like:</p><pre>“18:00, 10 Mar 2015”</pre><p>In the format string, writing one more `M` for the month will print the whole name of the month. Like:</p><pre>dateFormatter.dateFormat = “HH:mm, d MMMM yyyy”</pre><p>will give us:</p><pre>“18:00, 10 March 2015”</pre><h3>What about localization?</h3><p>`NSLocale` is another partner of `NSDateFormatter`. You can provide a locale for the language you want and date formatter will format the date according to it. For example:</p><pre>dateFormatter.locale = NSLocale(localeIdentifier:”tr”)</pre><p>will give us:</p><pre>“18:00, 10 Mart 2015”</pre><p>and</p><pre>dateFormatter.locale = NSLocale(“ru”)</pre><p>will give us:</p><pre>“18:00, 10 марта 2015”</pre><p>You can also provide the locale which is set in system settings like:</p><pre>dateFormatter.locale = NSLocale.currentLocale()</pre><p>So that you can have a date formatted with the current locale of the user’s choice!</p><h3>Conclusion</h3><p>These are the basic tips &amp; tricks about date formatting on iOS!</p><p>And you can find the playground file of this post <a href="https://gist.github.com/iltercengiz/13d13cb5b684762c8323">here</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=993d12cdd2f3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/objective-tidbits/date-formatter-993d12cdd2f3">Date Formatter</a> was originally published in <a href="https://medium.com/objective-tidbits">Objective Tidbits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Masking views]]></title>
            <link>https://medium.com/objective-tidbits/masking-views-ea09425b95ad?source=rss-ef4293c548f5------2</link>
            <guid isPermaLink="false">https://medium.com/p/ea09425b95ad</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[image-masking]]></category>
            <dc:creator><![CDATA[Ilter Cengiz]]></dc:creator>
            <pubDate>Fri, 16 Dec 2016 04:58:49 GMT</pubDate>
            <atom:updated>2016-12-16T04:58:49.296Z</atom:updated>
            <content:encoded><![CDATA[<p>Apart from `cornerRadius`, we can easily mask any view with any shape and path using `UIBezierPath` and `CAShapeLayer`. This provides us much more flexibility in laying out our subviews and making them as odd as possible.</p><h3>Rounding corners</h3><p>Any views’ corners can be rounded like so;</p><pre>view.layer.cornerRadius = 8.0</pre><p>But, what if we wanted to round only two corners and let the other corners be squared? At this point `UIBezierPath` and `CAShapeLayer` come to the rescue!</p><p>First we need to create the path of our mask with the desired corners rounded.</p><pre>UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.titleLabel.bounds                                               byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight                                                     cornerRadii:CGSizeMake(8.0, 8.0)];</pre><p>Then we create the shape layer object with an adjusted frame to be set as mask layer of our view.</p><pre>CAShapeLayer *maskLayer = [CAShapeLayer new];maskLayer.frame = self.titleLabel.bounds;</pre><p>At this point, the only thing we need to do is to set the path of our mask layer.</p><pre>maskLayer.path = maskPath.CGPath;</pre><p>Being a Core Animation framework class, `CAShapeLayer`’s `path` takes a `CGPath`.</p><p>Now we have our mask to be applied. The only task left is to apply it! It’s done so:</p><pre>self.view.layer.mask = maskLayer;</pre><p>We have a brand new view whose top left and top right corners are rounded with a radius of `8.0`.</p><h3>Star</h3><p>We want to our image view to be masked with a star. First create the star shaped bezier path, like so:</p><blockquote>I used <a href="https://www.paintcodeapp.com/">PaintCode</a> to create this bezier path. You can find the paint code drawing file <a href="https://gist.github.com/iltercengiz/173060f878c0373d0b9a/raw/e7ec1e1553ba17de2bd7b94235ce8fff92e3b482/Star.pcvd">here</a>.</blockquote><pre>UIBezierPath* starPath = UIBezierPath.bezierPath; [starPath moveToPoint: CGPointMake(128, 0)];[starPath addLineToPoint: CGPointMake(156.58, 88.66)];[starPath addLineToPoint: CGPointMake(249.74, 88.45)];[starPath addLineToPoint: CGPointMake(174.24, 143.03)];[starPath addLineToPoint: CGPointMake(203.24, 231.55)];[starPath addLineToPoint: CGPointMake(128, 176.62)];[starPath addLineToPoint: CGPointMake(52.76, 231.55)];[starPath addLineToPoint: CGPointMake(81.76, 143.03)];[starPath addLineToPoint: CGPointMake(6.26, 88.45)];[starPath addLineToPoint: CGPointMake(99.42, 88.66)];[starPath closePath];</pre><blockquote>Also, I assumed that `imageView` is 256x256 points in size.</blockquote><p>Then, create the layer and set its path:</p><pre>CAShapeLayer *starShape = [CAShapeLayer new];starShape.frame = imageView.bounds;    starShape.path = starPath.CGPath;</pre><p>And finally set `imageView`’s mask layer:</p><pre>imageView.layer.mask = starShape;</pre><p>The result is:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/375/1*x_C1Is0HlNjqPivw2Eg5YA.png" /></figure><p>You can find the gist of the content above <a href="https://gist.github.com/iltercengiz/173060f878c0373d0b9a">here</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ea09425b95ad" width="1" height="1" alt=""><hr><p><a href="https://medium.com/objective-tidbits/masking-views-ea09425b95ad">Masking views</a> was originally published in <a href="https://medium.com/objective-tidbits">Objective Tidbits</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[NSDailyReport — @5.0]]></title>
            <link>https://medium.com/z-raporu/nsdailyreport-5-0-76d5e6263eca?source=rss-ef4293c548f5------2</link>
            <guid isPermaLink="false">https://medium.com/p/76d5e6263eca</guid>
            <category><![CDATA[viper]]></category>
            <category><![CDATA[try]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Ilter Cengiz]]></dc:creator>
            <pubDate>Mon, 28 Mar 2016 20:02:55 GMT</pubDate>
            <atom:updated>2016-03-28T20:49:53.042Z</atom:updated>
            <content:encoded><![CDATA[<h4>Yaptıklarım</h4><ul><li>Try?</li></ul><p><em>try kullanımını guard ile nasıl yaparım?</em> diye deneyeyim dedim. <em>catch</em> ile işim olmazsa ve sadece gelen değer ile devam edilmeli ise kullanılabilir diye düşünüyorum. Yanlış bir kullanım ise uyarırsanız sevinirim. :) Fakat daha öncesinde bu tarz bir kullanım gördüğümü hatırlıyorum. <em>Aklım benimle oyun oynamıyorsa tabii.</em> Kod parçacığı aşağıda, playground ise <a href="https://github.com/iltercengiz/Playgrounds">GitHub reposunda</a>.</p><pre>func throwing() throws -&gt; Int {<br>    throw NSError(domain: &quot;asdasd&quot;, code: 4, userInfo: nil)<br>//    return 5<br>}<br><br>func test() {<br>    guard let number = try? throwing() else {<br>        print(&quot;Failed&quot;)<br>        return<br>    }<br>    print(number)<br>}<br>test()</pre><h4>Okuduklarım</h4><ul><li><a href="https://medium.com/u/3c5873e4e2de">Seyfeddin Bassarac</a> çok güzel bir derleme yapmış. ‘Apple uygulama geliştiricilerinin cephanesi’ niteliğindeki kaynak:</li></ul><h3>Seyfeddin Bassarac on Twitter</h3><p>Apple Geliştiricisinin Alet Çantası https://medium.com/@seyfoyun/apple-geli%C5%9Ftiricisinin-alet-%C3%A7antas%C4%B1-c9909ae306f7#.9rc2vqt2j ...</p><p>Benzer bir listeyi zamanında ben de Quora’da bir soruya <a href="https://www.quora.com/What-are-some-useful%E2%80%933rd-party-tools-experienced-iOS-engineers-use-for-development/answer/Ilter-Cengiz">cevap</a> olarak yazmıştım.</p><ul><li>Şu sıralar VIPER mimarisi ile ilgileniyorum ve (en azından şimdilik) bu mimarinin iOS app projelerinde MVC’nin yerini alacağını düşünüyorum. Yeni başlarken oldukça karmaşık gelebiliyor ama şu iki kaynağı oldukça başarılı buldum:</li></ul><ul><li><a href="https://www.objc.io/issues/13-architecture/viper/">Architecting iOS Apps with VIPER</a></li><li><a href="https://swifting.io/blog/2016/03/07/8-viper-to-be-or-not-to-be/">swifting.io</a></li></ul><ul><li>Geçtiğimiz hafta iOS 9.3 çıktı çıkmasına da bazı <em>eski(!)</em> cihazlarda güncelleme sonrası aktivasyonda sıkıntı olması nedeniyle Apple bu güncellemeyi söz konusu <em>eski(!)</em> cihazlar için geri çekmişti. Bugün güncellenmiş versiyonunu tekrar yayına almış. <em>Güncellemeleri kontrol etmekte fayda var.</em></li></ul><p>Developer hesabı olanlar doğrudan şuradan da indirebilir tabii ki:</p><p><a href="https://developer.apple.com/ios/download/">Download - iOS - Apple Developer</a></p><p>VIPER ve Swift ile maceramdan kesitlerle tekrar birlikte olmak dileklerimle. <em>:)</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=76d5e6263eca" width="1" height="1" alt=""><hr><p><a href="https://medium.com/z-raporu/nsdailyreport-5-0-76d5e6263eca">NSDailyReport — @5.0</a> was originally published in <a href="https://medium.com/z-raporu">Z Raporu</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[NSDailyReport — @4.0]]></title>
            <link>https://medium.com/z-raporu/nsdailyreport-4-0-4a4ec62d7e0a?source=rss-ef4293c548f5------2</link>
            <guid isPermaLink="false">https://medium.com/p/4a4ec62d7e0a</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Ilter Cengiz]]></dc:creator>
            <pubDate>Wed, 23 Mar 2016 18:20:23 GMT</pubDate>
            <atom:updated>2016-03-23T20:13:20.342Z</atom:updated>
            <content:encoded><![CDATA[<p>Bir süredir yazamadım. İş yoğunluğu yüzünden ve boş vakitlerimde de bir şeyler okumak/yazmak yerine daha çok vakit öldürmem yüzünden yazmaya pek fırsatım olmadı. Kayda değer de pek bir şey yapmamışım aslında dönüp düşününce. :)</p><h4>Yaptıklarım</h4><ul><li>Hafta sonu ‘UICollectionViewLayout’ ile uğraştım. Bir arkadaşımın isteği üzerine anlık ilerleyen ve zaman bazlı özelleştirilmiş bir layout üzerine çalıştım. Tamamen Swift ile yazdım ve şu kaynaklardan faydalandım:</li></ul><ol><li><a href="https://developer.apple.com/library/ios/documentation/UIKit/Reference/UICollectionViewLayout_class/">UICollectionViewLayout class reference</a></li><li><a href="https://github.com/erichoracek/MSCollectionViewCalendarLayout">MSCollectionViewCalendarLayout</a></li></ol><ul><li>Önceki yazılarımda da bahsettiğim gibi, projemizi Objective-C ile geliştiriyorduk. Son ekleyeceğimiz özellikleri Swift ile geliştirmeye karar vermiştim. Bugün de bu yeni eklenen kısımların testleri ile uğraştım. Buradaki en zor kısım, Objective-C ve Swift kaynaklarının birlikte olduğu bir target’taki sınıflara test sınıflarının erişimi idi.</li></ul><p>Test için de ayrı bir ‘Bridging header’ oluşturulması gerekiyordu, fakat sonrasında uygulama target’ının derlenmesi için her iki ‘Bridging header’ın da aynı içeriğe sahip olması gerektiği oldukça şaşırtıcı oldu. <em>Kaçırdığım bir şey varsa aydınlatın lütfen. :)</em></p><p>Bu konuyla ilgili araştırma yaparken şu Stackoverflow <a href="http://stackoverflow.com/a/32009368">sorusu</a> yardımcı oldu:</p><p><a href="http://stackoverflow.com/a/32009368">&quot;No such module&quot; when using @testable in Xcode Unit tests</a></p><blockquote>Make sure that all required classes are members of your test target</blockquote><blockquote>Make sure that you have added all the required libraries</blockquote><p>Biraz daha araştırdığımda ise şu örnek <a href="https://github.com/gergelyorosz/swift-objective-c-mixed-project">projeye</a> denk geldim:</p><p><a href="https://github.com/gergelyorosz/swift-objective-c-mixed-project">gergelyorosz/swift-objective-c-mixed-project</a></p><h4>Okuduklarım</h4><ul><li>Pazartesi günü yeni iPhone SE ve iPad Pro tanıtımı ile birlikte iOS 9.3 ve Xcode 7.3 de çıktı. Sıkıntısız bir şekilde App Store’dan güncelledim fakat herkes için o kadar sıkıntısız değilmiş anlaşılan. <em>Apple artık iyi iş yapamıyor mu yoksa?</em></li></ul><p>Erica Sadun <a href="http://ericasadun.com/2016/03/22/xcode-upgrades-lessons-learned/">yazmış</a>:</p><p><a href="http://ericasadun.com/2016/03/22/xcode-upgrades-lessons-learned/">Xcode Upgrades: Lessons learned</a></p><ul><li>Swift 2.2 de geldi ve beraberinde #selector kullanımını getirdi.</li></ul><p><a href="https://medium.com/p/81c8a8b10df3">Swift: Selector syntax sugar</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4a4ec62d7e0a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/z-raporu/nsdailyreport-4-0-4a4ec62d7e0a">NSDailyReport — @4.0</a> was originally published in <a href="https://medium.com/z-raporu">Z Raporu</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>