UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

UIImage ile görselleri çağırma

Bu noktada, storyboard'umuzda görselleri seçebileceğimiz orjinal bir tablo ekranı denetleyicimiz ve bir de detay ekranı denetleyicimiz var. Sonraki amacımız, herhangi bir tablo satırına dokunduğumuzda, seçtiğimiz görseli içeren detay ekranını göstermek olacak.

Bunu yapmak için, ViewController'a başka bir ismi özel olarak verilmiş bir metod eklememiz gerekiyor. Bunun adı tableView(_, didSelectRowAt:). Hangi satırla çalıştığımızı söyleyen cellForRowAt gibi bir IndexPath değeri alır. Bu kez biraz daha fazla işimiz var:

  1. Yüklenecek görselin adını tutacak olan DetailViewController içinde bir özellik oluşturmamız gerekiyor.
  2. didSelectRowAt metodunu uygulayacağız, böylece storyboard'tan bir DetailViewController yüklenecek.
  3. Son olarak, DetailViewController'daki viewDidLoad() metodunun içini dolduracağız. Öyle ki bu da, daha önce verdiğimiz isme göre görsel ekranının içine bir görsel yükleyecek.

Şimdi bunları ilkinden başlayarak, sırasıyla çözelim: DetailViewController içinde, yüklenecek görsellerin adını tutan bir özellik oluşturalım.

Bu özellik bir string olacak –yüklenecek görselin adı– ama bu bir optional olmak zorunda, çünkü ekran denetleyicisi ilk oluşturulduğunda, henüz varolmuş değil. Onu doğrudan kuracağız, ama yine de hayata boş olarak başlayacak.

Şimdi bu özelliği DetailViewController içine, tam @IBOutlet satırının altına ekleyin:

var selectedImage: String?

İlk görev tamamlandı; sıra ikincisinde: didSelectRowAt özelliğini uygulayalım, böylece o da storyboard'tan bir DetailViewController yüklesin.

Detay ekranı denetleyicisini oluşturduğumuzda, instantiateViewController(withIdentifier:) adlı metodu kullanarak storyboard'tan onu yüklememize izin verecek olan “Detail” storyboard ID'si vermiştiniz. Her ekran denetleyicisi storyboard adında bir özelliğe sahiptir; ya yüklendiği storyboard'tur veya nil değerindedir. ViewController durumunda ise, bu özellik Main.storyboard olacaktır. Bu da, detay ekranı denetleyicisini içeren storyboard'la aynıdır; dolayısıyla oradan yüklüyor olacağız.

Bu görevi, üç küçük görev haline parçalayabiliriz ki, bunlardan ikisi yeni:

  1. Storyboard'umuzdan detay ekranı denetleyici düzenlemesini yükle.
  2. pictures dizisinden doğru elemanı, selectedImage özelliği olacak şekilde ayarla.
  3. Yeni ekran denetleyicisini göster.

Bunların ilki, instantiateViewController çağrısı ile yapılıyor, ama iki küçük zorluğu var. Birincisi, Apple'ın UIViewController tipinden edindiğimiz storyboard özelliği üzerinde onu çağırıyoruz. Ama o bir optional'dır, çünkü Swift, bir storyboard'dan geldiğimizi bilmiyor. Bu yüzden, ? kullanmamız gerekiyor; tıpkı hücremizin metin etiketini ayarladığımızdaki gibi: "Bunu yapmayı dene, ama eğer bir sorun varsa hiçbir şey yapma".

İkincisi, instantiateViewController() metodunun her şey doğru bir şekilde çalışırsa bize geri bir DetailViewController gönderecek olmasına rağmen, Swift onun geriye bir UIViewController döndüreceğini düşünecek, çünkü neyin ne olduğunu bilen storyboard'ın içinde göremeyecek.

Eğer programlama konusunda yeniyseniz, bu biraz kafa karıştırıcı görünebilir, o yüzden bir örnek kullanarak açıklamaya çalışayım. Diyelim ki, bu gece bir randevunuz var ve benden bir etkinliğe bir çift bilet ayarlamamı istiyorsunuz. Gidiyorum ve biletleri buluyorum. Ardından onları bir zarfla size veriyorum. Üzerime düşen kısmını yerine getirdim: Bilet istediniz, biletleri temin ettim. Peki ya biletler ne içindi; bir spor etkinliği için mi? Veya bir opera? Ya da tren bileti mi? Bunu anlamanın tek yolu, zarfı açıp bakmak.

Swift'te de aynı sorun var: instantiateViewController() metodu, UIViewController dönüş tipine sahip; dolayısıyla Swift bununla herhangi bir ekran denetleyicisi yarattığı sürece, aslında o bir UIViewController olur. Bu bizim için bir sorun çıkarır, çünkü DetailViewController içinde oluşturduğumuz özelliği ayarlamak istiyoruz. Çözüm: Sahip olduğu şeyin, sandığı şey olmadığını Swift'e söylememiz gerekiyor.

Bunun teknik terim karşılığı "typecasting"dir (tipleme): Yani Swift'ten, bir değere başka bir tipmiş gibi davranmasını istemek. Swift dili birçok yolla bunu yapabilir, ama biz en güvenli versiyonunu kullanacağız: Bu fiilen, "Lütfen bunu DetailViewController'mış gibi işle, ama eğer başarısız olursa, hiçbir şey yapma ve devam et." anlamına gelir.

Detay ekranı denetleyicisini bir kez ele aldığımızda, onun selectedImage özelliğini pictures[indexPath.row] eşit olacak şekilde ayarlayabiliriz; tam da cellForRowAt içinde yaptığımız gibi. Bu iş, kolay olanıydı.

Üçüncü küçük adım, kendini gösterecek olan yeni bir ekran yapmak. Ekran denetleyicilerinin, çağırılacağı storyboard'u içereceği veya nil olacağı bir optional storyboard özelliğine sahip olduklarını zaten görmüştünüz. İşte onlar aynı zamanda, eğer varsalar içlerinde olacakları bir kılavuz denetleyicisini, ama eğer yoksalar nil değerini içeren bir optional navigationController özelliğine de sahiptirler.

Bu bizim için mükemmel bir şeydir, çünkü kılavuz denetleyicileri ekranların gösteriminden sorumludurlar. Tabi bir çok uygulamanın en üstünde görebileceğiniz hoş gri çubuğu da sağlarlar, ama onlar aynı zamanda kullanıcıların aralarında geçiş yapabileceği büyük bir ekran yığınının sağlanmasından da sorumludurlar.

Varsayılan olarak, storyboard'da onlar için oluşturduğunuz ilk ekran denetleyicisini barındırırlar, ama yeni ekranlar yaratılırken, Settings'de gördüğünüz gibi yumuşak bir şekilde kaydırılabilen kılavuz denetleyicisi yığınının üzerine onları sürebilirsiniz. Daha fazla ekran sürülmeye devam ederken, kaymaya devam ederler. Kullanıcılar bir ekran geri gittiklerinde –örneğin Back (Geri) butonuna basarak veya soldan sağa doğru kaydırarak– kılavuz denetleyicisi otomatik olarak eski ekran denetleyisini yok eder ve hafızada yer açar.

Bu üç küçük adım, yeni metodu tamamlar; o zaman kod yazma zamanı geldi. Lütfen ViewController.swift dosyasına şu metodu ekleyin; kolayca anlaşılabilmesi için yorumlar ekledim:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // 1: try loading the "Detail" view controller and typecasting it to be DetailViewController
    if let vc = storyboard?.instantiateViewController(withIdentifier: "Detail") as? DetailViewController {
        // 2: success! Set its selectedImage property
        vc.selectedImage = pictures[indexPath.row]

        // 3: now push it onto the navigation controller
        navigationController?.pushViewController(vc, animated: true)
    }
}

Bir an için, if let satırına biraz daha yakından bakalım. Başarısız olma ihtimali olan üç parça içeriyor: storyboard özelliği bir ihtimal nil olabilir (? durumu, satırın geri kalanının çalıştırılmasını durduracaktır). instantiateViewController() çağrısı başarısız olabilir, eğer biz “Fzzzzz” veya başka bir geçersiz storyboard ID'si istemişsek. Tipleme de –as? kısmı– hata verebilir, çünkü geriye farklı tipte bir ekran denetleyicisi almış olabiliriz.

Dolayısıyla bu bir satırdaki üç şey, potansiyel olarak başarısızlık ihtimali taşıyor. Eğer tüm adımları doğru bir şekilde izlediyseniz, hiçbiri başarısız olmayacak, ama potansiyel olarak bu ihtimale sahipler. if let yapısının akıllıca olduğu yer burası işte: Eğer bunların herhangi birisi nil değeri döndürürse (yani başarısız olursa), if let parantezlerinin içindeki kod çalıştırılmayacak. Bu, herhangi bir eyleme geçmeden programınızın güvende olmasını garantiler.

Sonuçlara bir göz atmadan önce, geriye yapılması gereken sadece küçük bir şey kaldı: DetailViewController içindeki görsel ekranına, görselin gerçekten yüklenmesini sağlamamız gerekiyor.

Bu yeni kod, UIImage olarak adlandırılan yeni bir veri tipinden yararlanacak. Bu, UIImageViewin çağrıştırdığı gibi, isminde "View" barındırmıyor. Yani görüntüleyebileceğin bir şey değil; aslında kullanıcılara görünür olan birşey değil. UIImage daha çok, PNG veya JPEG gibi görsel verileri yükleyebileceğiniz bir veri tipidir.

Bir UIImage oluşturduğunuzda, yükleyeceğiniz görselin adını belirlemenizi sağlayan named adında bir parametre alır. UIImage, uygulamanızın içinde bu dosya adını arar ve onu yükler. Burada ViewControllerdan gönderilen selectedImage özelliğine aktararak, kullanıcı tarafından seçilen görseli yükler.

Yine de selectedImage özelliğini doğrudan kullanamayız. Hatırlarsanız, aşağıdaki gibi onu oluşturduk:

var selectedImage: String?

Bu ?, onun bir değer içerebileceği veya içermeyeceği anlamına gelir ve Swift dili, onları kontrol etmeden önce, bu "belkileri" kullanmanıza izin vermez. if let için bu bir başka fırsattır: selectedImage özelliğinin bir değere sahip olduğunu kontrol edebilir ve eğer sahipse, kullanım için onu çekebiliriz; aksi durumda ise, hiçbir şey yapmaz.

DetailViewController içindeki viewDidLoad() metoduna, super.viewDidLoad() çağrısından sonra şu kodu ekleyin:

if let imageToLoad = selectedImage {
    imageView.image  = UIImage(named: imageToLoad)
}

İlk satır, selectedImage içindeki seçeneği kontrol edip açar. Bir şekilde selectedImage özelliği nil ise (teorik olarak asla öyle olmaması gerekiyor), o zaman imageView.image satırı hiçbir zaman çalıştırılmayacaktır. Ama eğer bir değere sahipse, imageToLoad içine yerleştirilecek, ardından UIImage'e aktarılacak ve yüklenecektir.

Tamam, hepsi bu kadar: Uygulamayı çalıştırmak için Play butonuna veya Cmd+R tuşlarına basın şimdi ve deneyin bakalım! Kaydırılabilen görsellerin herhangi birini seçebilmeniz ve tam ekran görüntüleyebilmeniz gerekiyor.

Kılavuz çubuğunda, ViewController'a geri dönmemizi sağlayan bir Back butonu olduğu dikkatinizi çekti mi? Dikkatli bir şekilde tıklayıp sürüklerseniz, ekranı kaydırma hareketini de oluşturduğunuzu göreceksiniz. Ekranın en sol köşesine tıklayıp, sağa çekin; tıpkı telefonunuzda parmaklarınızla yaptığınız gibi.

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.