Showing posts with label Swift. Show all posts
Showing posts with label Swift. Show all posts

Saturday, September 8, 2018

Berkenalan dengan CocoaPods

What is CocoaPods?
Cocoapods adalah dependency-manager untuk XCode projects. Cara penggunaan yang mudah dan sederhana membuat Cocoapods banyak digunakan oleh Cocoa user. Oke, mungkin masih ada yang bingung apa itu dependency-manager. Dependency manager adalah suatu module yang akan mengatur dependency, sebut saja library, yang akan kita gunakan di project. Misalnya saja kita ingin membuat sebuah Picker dengan suatu tampilan yang bisa dicustomize, kita punya 2 pilihan yaitu membuatnya sendiri atau menggunakan 3rd party library, misalnya saja dari Kingfisher yang dibahas di artikel ini.
"Do not reinvent the wheel"
Familiar dengan kata-kata di atas? Dalam kasus ini kita bisa saja membuat Picker itu jika tidak ada orang di luar sana yang telah membuat dan membagikannya, namun jika ada library yang telah dibuat, dibagikan, dan memenuhi kebutuhan kita maka lebih baik jika kita menggunakannya. Dengan begitu maka kita bisa mengalihkan waktu pembuatan Picker untuk proses lain yang lebih membutuhkan. Cara paling mudah untuk menggunakan library yang sudah dibuat dan dibagikan oleh orang lain di github adalah menggunakan CocoaPods

Why use CocoaPods?
  1. Mudah di-install
  2. Mudah digunakan
  3. Banyak library yang sudah support instalasi menggunakan CocoaPods
  4. Besar komunitasnya
  5. Reliable


Installing CocoaPods
Instalasi sangat mudah, cukup buka terminal dan ketikkan line berikut :

sudo gem install cocoapods

How to use CocoPods
Buka terminal, lalu arahkan current directory ke dalam project anda lalu ketikkan line berikut :

pod init

Contohnya : 


Selanjutnya, di file project anda akan ada beberapa file baru yaitu Podfile, Podfile.lock, [nama_project].xcoworkspace, dan folder Pods.
Anda cukup memperhatikan Podfile dan [nama_project].xcoworkspace.

Podfile adalah tempat anda mendaftarkan library yang akan digunakan di project.
[nama_project].xcoworkspace adalah file yang perlu anda gunakan saat membuka project. Anda wajib  menggunakan .xcoworkspace jika menggunakan pods agar library yg anda gunakan bisa di-load ke project. Jika menggunakan .xcodeproj maka library yang diinstall mengunakan CocoaPods tidak akan dikenali di project.


Is there any alternatives?
Tentu saja ada alternatif lain dari CocoaPods, alternatif ini adalah Carthage dan Swift Package Manager

Sharing is Caring

References :
https://cocoapods.org/
https://github.com/CocoaPods
https://github.com/Carthage/Carthage
https://github.com/apple/swift-package-manager

Displaying & Caching Image Using Kingfisher

Image atau gambar adalah hal yang tidak bisa dihindari dan pasti selalu digunakan dalam setiap front-end software development tidak peduli platform apa yang digunakan, baik itu mobile, desktop, ataupun web. Pada kesempatan kali ini saya akan membahas dalam platform mobile, khususnya iOS. 

Dalam pembuatan aplikasi mobile pasti kita akan membutuhkan image untuk mempercantik sekaligus menjelaskan sesuatu, misalnya untuk melakukan send email kita menggunakan button bergambar amlop. Salah satu hal penting yang tidak terlihat dalam software development mobile adalah memperhatikan jumlah data yang digunakan. Tentunya yang banyak memakan data adalah jika kita menggunakan image yang tidak disimpan di dalam installer (.ipa). Tentu saja jika user menyadari bahwa aplikasi kita menggunakan banyak sekali data, maka bukan tidak mungkin user akan berhenti menggunakan aplikasi tersebut.

Solusi dari permasalahan ini adalah menggukan cache. Apa itu cache? Cache adalah suatu cara untuk menyimpan data yang sudah diproses oleh user. Data ini suatu waktu bisa saja digunakan lagi tanpa perlu melakukan proses komputasi ulang. Untuk lebih jelasnya bisa dibaca di dewaweb dan techtarget.

Salah satu library yang populer di iOS (Swift) development adalah Kingfisher. Kingfisher merupakan library yang bisa membantu kita menampilkan image melalui URL dan sekaligus melakukan caching pada image tersebut, sehingga jika akan digunakan lagi maka aplikasi tidak akan me-load ulang gambar itu melalui URL-nya.

Install Kingfisher
Jika menggunakan CocoaPods, maka cukup dengan menambahkan line berikut di Podfile :

pod 'Kingfisher', '~> 4.0'


Jika menggunakan Carthage, maka tambahkan line berikut di Cartfile :

github "onevcat/Kingfisher" ~> 4.0

Jika menggunakan Swift-Package-Manager, maka tambahkan liner berikut di Package.swift :

import PackageDescription

let package = Package(
    name: "YourAwesomeSoftware",
    dependencies: [
        .Package(url: "https://github.com/onevcat/Kingfisher.git",
                 majorVersion: 4)
    ]
)

Fitur-fitur dari Kingfisher
  1. Unduhan gambar dan caching tidak sinkron.
  2. Jaringan berbasis URLSession. Prosesor dan filter gambar dasar disediakan.
  3. Cache multi-layer untuk memori dan disk.
  4. Tugas mengunduh dan memproses yang tidak dapat dibatalkan untuk meningkatkan kinerja.
  5. Komponen independen. Gunakan sistem pengunduh atau caching secara terpisah sesuai kebutuhan Anda.
  6. Mengambil gambar terlebih dahulu dan menampilkannya dari cache nanti bila diperlukan.
  7. Ekstensi untuk UIImageView, NSImage dan UIButton untuk langsung mengatur gambar dari URL.
  8. Animasi transisi internal saat mengatur gambar.
  9. Placeholder yang dapat disesuaikan saat memuat gambar.
  10. Pemrosesan gambar yang dapat diperluas dan dukungan format gambar.
Cara menggunakan
Cara paling dasar dalam menggunakan Kingfisher adalah menggunakannya di ImageView.
let url = URL(string: "url_of_your_image")
imageView.kf.setImage(with: url)
Tentu saja kingfisher tidak hanya bisa digunakan di ImageView saja, anda juga bisa menggunakannya pada komponen lain, misalnya UIButton, custom-made-view, dan lainnya menggunakan cara yang sama.

Sekian informasi yang dapat saya bagikan, jika ada kesalahan, masukan, ataupun pertanyaan silakan tinggalkan di komentar atau kirim email

Sharing is Caring

References :
https://github.com/onevcat/Kingfisher
https://github.com/onevcat/Kingfisher/wiki/Installation-Guide
https://searchstorage.techtarget.com/definition/cache
https://www.dewaweb.com/blog/penjelasan-cache-dan-jenis-jenisnya/

Tuesday, March 15, 2016

How to Transfer Objects Between UIViewController

Dalam pengembangan aplikasi iOS, seringkali kita membutuhkan untuk mentransfer data dari satu view ke view lainnya. Misalnya pada kasus ketika kita ingin menampilkan informasi detil sebuah user profile hasil dari pencarian user. Bagaimana cara kita melakukan hal tersebut pada iOS? Kesempatan kali ini saya ingin berbagi cara sederhana untuk melakukannya dengan menggunakan bahasa pemrograman Swift dan storyboard.

Pada pengembangan aplikasi iOS menggunakan Xcode, alur dari view aplikasi dapat didisain dengan menggunakan fitur storyboard. Storyboard merupakan fitur yang sangat bermanfaat karena pengembang aplikasi dapat merancang bentuk dan alur dari aplikasi secara independen tidak tergantung dengan kode logika dari aplikasi. Kode logika aplikasi dapat disambungkan dan dilepaskan dengan storyboard dengan usaha yang relatif minimal (cukup Ctrl+Drag). Saya sempat memiliki pengalaman ketika project files saya corrupt sehingga saya harus mendisain ulang storyboard beserta view-nya dari awal. Ketika sudah selesai, storyboard dan kode logika aplikasi dapat disambungkan kembali. Agak banyak, namun setidaknya tidak harus mengkodekan ulang. :)

Gambar di atas menunjukkan storyboard yang saya gunakan pada artikel kali ini. Storyboard aplikasi ini cukup sederhana di mana hanya terdapat 2 view. Pada view pertama hanya terdapat sebuah tombol yang ketika ditekan akan menginisiasi perpindahan view ke view pada sebelah kanan melalui show segue (panah). Perpindahan data di sini hanya akan memindahkan nilai yang dimasukkan pada textfield sehingga label "Nilai" pada view sebelah kanan akan berubah menjadi nilai apapun yang dimasukkan di textfield view pertama. Berilah nama pada show segue tersebut dengan nama yang identik dalam scope 1 project. Pada contoh ini saya beri nama "transferDataSegue". Buat 2 subclass dari UIViewController dan asosiasikan dengan masing-masing view pada storyboard. Saya mengasosiasikan view pertama dengan StartViewController dan view kedua dengan FinishViewController.


Bind textfield di view pertama ke IBOutlet pada StartViewController. Kemudian bind pula label di view kedua ke IBOutlet pada FinishViewController. Buat sebuah variable pada FinishViewController untuk meletakkan nilai yang dipindahkan dari StartViewController. Kunci dari transfer data antarview pada iOS adalah pada fungsi prepareForSegue dari UIViewController. Override fungsi tersebut kemudian isi agar sesuai seperti gambar berikut:

Fungsi prepareForSegue ini akan selalu dipanggil setiap kali terdeteksi adanya transisi dari sebuah view ke view yang lain. Jika segue yang dihubungkan lebih dari 1, maka transisi dapat terjadi beberapa kemungkinan. Oleh karena itu kita membutuhkan identifier unik untuk segue yang dibahas sebelumnya. Pada fungsi ini langkah pertama kita harus menentukan segue mana yang akan dieksekusi, dengan cara memeriksa identifier-nya. Variabel identifier pada object segue berisikan informasi identifier yang sedang dijalankan.

Setelah kita sudah memperoleh object segue yang sedang dieksekusi, kita pastikan terlebih dahulu apakah object segue tersebut memiliki kaitain dengan UIViewController tujuan. UIViewController tujuan memiliki relasi dengan sebuah segue object yaitu pada variabel destinationViewController yang merupakan FinishViewController. Jika sudah tervalidasi, maka proses transfer data antarview cukup dilakukan semudah assignment variabel biasa. Pada FinishViewController, load nilai yang telah diterima dengan meng-assign-nya ke IBOutlet textfield pada fungsi viewDidLoad.

Silahkan coba dijalankan. Sangat mudah bukan? ;)




Friday, December 11, 2015

Introduction to CocoaPods

Saat kita membuat sebuah project aplikasi tentunya kita akan banyak menggunakan Library dan plugins yang nantinya kita butuhkan untuk mempermudah dalam pengembangan aplikasi. Untuk memudahkan kita dalam memanage kumpulan Library tersebut kita membutuhkan sistem depedency manager. Begitu juga saat kita memulai Ios project kita akan menggunakan depedency manager "Cocoapods".

Cocoapods adalah sebuah depedency manager untuk Swift atau Objective-C project yang memiliki banyak kumpulan Library yang memungkinkan untuk mengembangkan aplikasi secara elegant.

Kita langsung saja ke proses instalasi cocoapods ke project IOS,

Instalasi

Sebelum melakukan instalasi pastikan Ruby sudah terinstall di device kalian, hal ini dikarenakan Cocoapods dibangun menggunakan Ruby.

setelah instalasi Ruby selesai, jalankan script berikut di terminal :

$ sudo gem install cocoapods
Sekarang cocoapods sudah terinstall di device kalian.

Membuat Podfile

Podfile yang nantinya akan menampung seluruh list Library yang akan kita gunakan didalam project. Ada 2 cara untuk membuat Podfile

  1. Buat file kosong bernama Podfile didalam project yang akan digunakan.
  2. Jalankan Pod init di project yang akan digunakan.
Masukan List Library

Berikut contoh dari list Library:
platform :ios, '7.0'
pod 'AFNetworking', '~> 2.0'


Dalam contoh ini kita akan menggunakan Library AFNetworking. sebelum kita menggunakan Library didalam project kita harus menambakan semua dependencies yang dibutuhkan ke dalam Podfile.

Untuk menginstall semua Library yang dibutuhkan jalan kan perintah berikut di terminal:

$ pod install

Setelah melakukan perintah diatas kita sudah bisa menggunakan semua library yang di list di Podfile.

Thanks.

Friday, September 18, 2015

Country Selection with Swift in iOS 8


Beberapa bulan terakhir ini, saya mulai mempelajari dan mengembangkan aplikasi iOS menggunakan bahasa Swift. Agar tidak lupa sekaligus menguji pengalaman yang saya peroleh, saya ingin mulai menuangkannya ke topik artikel-artikel saya ke depan. Pada artikel kali ini saya ingin membahas bagaimana cara membuat pilihan negara pada sebuah form menyerupai cara memilih negara pada Address Book iOS. Untuk lebih terbayang tujuan artikel ini, silahkan lihat video berikut ini:

Skenario yang ada pada video tersebut adalah pada scene pertama aplikasi menampilkan scene Edit Profile, di mana salah satu field profile adalah memilih negara. User kemudian memilih negara, lalu transisi ke scene selanjutnya yang muncul dari bawah berupa pilihan negara. Scene pemilihan negara ini tidak hanya berupa daftar negara saja, namun seperti pada Address Book dilengkapi juga dengan indeks huruf depan masing-masing nama negara untuk mempermudah navigasi user.
Gambar 1. Potongan Storyboard

 Storyboard yang saya gunakan pada dasarnya terdiri dari 3 scenes:
  1. EditProfileViewController, subclass dari TableViewController yang saya gunakan untuk scene edit profile.
  2. CountryHelperTableViewController, subclass dari TableViewController yang saya gunakan untuk scene dari pemilihan negara itu sendiri.
  3. NavigationViewController, scene ini bertugas menjembatani dengan EditProfileViewController. NavigationViewController ini berfungsi agar kita dapat melakukan transisi modal dengan lebih baik.
Buat sebuah Swift file bernama CountryHelperTableViewController.swift
import UIKit

class CountryHelperTableViewController: UITableViewController {
    
    var countries: [String]?
    var sectionTitles: [String]?
    var selectedCountryRowId: Int = 0
    var selectedCountryOffset: Int = 0
    var selectedSectionTitleRowId: Int = 0
    var selectedCountry: String?
    var generatedRows: Int = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        populateCountries()
        populateSectionTitles()
        setInitialCountrySelection()
        setSelectedCountryOffset()
    }
    
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        let indexPath = NSIndexPath(forRow: selectedCountryOffset, inSection: selectedSectionTitleRowId)
        self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Middle, animated: true)
    }
    
    func populateCountries() {
        countries = [String]()
        
        for code in NSLocale.ISOCountryCodes() as! [String] {
            let id = NSLocale.localeIdentifierFromComponents([NSLocaleCountryCode: code])
            let name = NSLocale(localeIdentifier: "en_US").displayNameForKey(NSLocaleIdentifier, value: id) ?? "Country not found for code: \(code)"
            countries!.append(name)
        }
        
        countries!.sort({ $0 < $1 })
    }
    
    func populateSectionTitles() {
        var countrySections = [String: String]()
        
        for country in countries! {
            countrySections[country[0]] = country[0]
        }
        
        var sortedCountrySections = [String]()
        
        for (key, value) in countrySections {
            sortedCountrySections.append(key)
        }
        
        sortedCountrySections.sort({ $0 < $1 })
        sectionTitles = sortedCountrySections
    }
    
    func setInitialCountrySelection() {
        for (index, country) in enumerate(countries!) {
            if country == selectedCountry {
                selectedCountryRowId = index
                
                for (sectionIndex, sectionTitle) in enumerate(sectionTitles!) {
                    if selectedCountry![0] == sectionTitle {
                        selectedSectionTitleRowId = sectionIndex
                        break
                    }
                }
                
                break
            }
        }
    }
    
    func setSelectedCountryOffset() {
        var offset: Int = 0
        
        for country in countries! {
            if country[0] == self.sectionTitles![selectedSectionTitleRowId] {
                if selectedCountry != country {
                    offset++
                } else {
                    break
                }
            }
        }
        
        selectedCountryOffset = offset
    }

    override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
 if section == tableView.numberOfSections() - 1 {
            return UIView(frame: CGRectMake(0, 0, 1, 1))
 } else {
     return nil
 }
    }

    override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        if section == tableView.numberOfSections() - 1 {
     return 1
        } else {
            return 0
        }
    }
    
    func rowsInPreviousSection(section: Int) -> Int {
        var rows = 0
        
        for country in self.countries! {
            if self.sectionTitles![section] == country[0] {
                break
            } else {
                rows++
            }
        }
        
        return rows
    }
    
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return self.sectionTitles!.count
    }
    
    override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return self.sectionTitles![section]
    }
    
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let indexTitle = self.sectionTitles![section]
        var numberOfRows = 0

        for country in self.countries! {
            if indexTitle == country[0] {
                numberOfRows++
            }
        }
        
        return numberOfRows
    }
    
    override func tableView(tableView: UITableView, sectionForSectionIndexTitle title: String, atIndex index: Int) -> Int {
        return index
    }
    
    override func sectionIndexTitlesForTableView(tableView: UITableView) -> [AnyObject]! {
        return self.sectionTitles
    }
    
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let row = indexPath.row
        let section = indexPath.section
        let prevSectionRows = rowsInPreviousSection(section)
        let cell = self.tableView.dequeueReusableCellWithIdentifier("CountryCell") as! UITableViewCell
        
        cell.textLabel?.text = countries![row + prevSectionRows]
        
        if selectedCountryRowId == row + prevSectionRows {
            cell.accessoryType = UITableViewCellAccessoryType.Checkmark
        } else {
            cell.accessoryType = UITableViewCellAccessoryType.None
        }
        
        return cell
    }
    
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        selectedCountryRowId = indexPath.row + rowsInPreviousSection(indexPath.section)
        tableView.reloadData()
    }
    
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "editProfileUnwindSegueWithValue" {
            if let destinationViewController = segue.destinationViewController as? EditProfileViewController {
                destinationViewController.selectedCountry = countries![selectedCountryRowId]
                destinationViewController.updateSelectedValues()
            }
        }
    }
    
}

Setelah selesai membuat class CountryHelperTableViewController, assign class tersebut ke scene paling kanan. Buat juga String extension seperti berikut ini untuk fungsi mengambil indeks huruf pertama pada nama negara.
import Foundation

extension String {
    
    subscript (i: Int) -> Character {
        return self[advance(self.startIndex, i)]
    }
    
    subscript (i: Int) -> String {
        return String(self[i] as Character)
    }
    
    subscript (r: Range) -> String {
        return substringWithRange(Range(start: advance(startIndex, r.startIndex), end: advance(startIndex, r.endIndex)))
    }
}

Method tableView(_:viewForFooterInSection:) dan tableView(_:heightForFooterInSection:) digunakan agar garis border horizontal dari TableView berakhir pada baris atau nama negara terakhir di dalam array. Perilaku default jika kedua method ini tidak diaplikasikan adalah garis border horizontal akan terus berulang hingga batas layar. Saya lebih suka jika garis horizontal berakhir sesuai dengan data.

Method viewDidLoad() dipanggil pada saat pertama kali saja untuk me-load daftar negara dari library Swift melalui method populateCountries(). Setelah negara-negara ter-load, kita membutuhkan daftar indeks huruf pertama dari masing-masing negara yang ter-load dengan menggunakan method populateSectionTitles(). Method setInitialCountrySelection() digunakan untuk menentukan posisi indeks yang sudah pernah dipilih oleh User dengan nilai default 0 jika User belum pernah melakukan pemilihan negara. Sedangkan method setSelectedCountryOffset() digunakan untuk menentukan offset ke-berapakah negara yang terpilih berdasarkan dari indeks section title. Method ini bermanfaat untuk menentukan TableViewCell manakah yang perlu ditandai dengan checkmark.

Method viewWillAppear() ini pada dasarnya bertujuan untuk melakukan autoscroll terhadap daftar negara, agar fokus dari view berada di tengah-tengah sesuai dengan negara yang pernah dipilih oleh User sebelumnya. Pada method ini tidak perlu lagi me-load daftar negara yang lengkap, karena daftar negara sudah di-load oleh viewDidLoad() untuk pertama kalinya. 

Method tableView(_:numberOfRowsInSection:) merupakan salah satu fungsi penting dalam menampilkan  daftar negara ini. Method inilah yang akan menyaring negara-negara yang sesuai dengan indeks huruf pertamanya. Sementara method tableView(_:sectionForSectionIndexTitle:) dan method sectionIndexTitlesForTableView() berguna untuk menampilkan bar horizontal di bagian kanan yang scene sebagai indeks huruf pertama dari masing-masing negara.

Sekian artikel saya tentang pengembangan iOS kali ini, semoga bermanfaat!