Indonesian (Bahasa Indonesia) translation by Uady (you can also view the original English article)
Dalam artikel pertama dari seri ini, kita meletakkan fondasi proyek dengan menyiapkan proyek dan membuat struktur aplikasi. Dalam artikel ini, kita memanfaatkan perpustakaan AFNetworking untuk berinteraksi dengan API Prakiraan.
pengantar
Dalam first installment dari seri ini, kita meletakkan dasar dari aplikasi cuaca. Pengguna dapat menambahkan lokasi mereka saat ini dan beralih antar lokasi. Dalam tutorial ini, kita akan menggunakan pustaka AFNetworking untuk menanyakan API Prakiraan untuk data cuaca dari lokasi yang sedang dipilih.
Jika Anda ingin mengikuti, Anda akan membutuhkan kunci API Prakiraan. Anda dapat memperoleh kunci API dengan mendaftar sebagai pengembang di Forecast. Pendaftaran gratis, jadi saya mendorong Anda untuk mencoba layanan cuaca Prakiraan. Anda dapat menemukan kunci API Anda di bagian bawah dasbor Anda (gambar 1).



1. Subclassing AFHTTPClient
Seperti yang saya tulis sebelumnya di artikel ini, kita akan menggunakan perpustakaan AFNetworking untuk berkomunikasi dengan API Forecast. Ada beberapa opsi ketika bekerja dengan AFNetworking, tetapi untuk membuat aplikasi kita menjadi bukti di masa mendatang, kita akan memilih kelas AFHTTPClient
. Kelas ini dirancang untuk menggunakan layanan web, seperti API Forecast. Meskipun kita hanya akan mengakses satu titik akhir API, masih berguna untuk menggunakan AFHTTPClient
seperti yang akan Anda pelajari dalam beberapa saat.
Disarankan untuk membuat subkelas AFHTTPClient
untuk setiap layanan web. Karena kita telah menambahkan AFNetworking ke proyek kita di tutorial sebelumnya, kita dapat segera memulai subclassing AFHTTPClient
.
Langkah 1: Buat Kelas
Buat kelas Objective-C baru, beri nama MTForecastClient
, dan menjadikannya subkelas AFHTTPClient
(gambar 2).



Langkah 2: Membuat Objek Singleton
Kita akan mengadopsi pola tunggal untuk membuatnya lebih mudah menggunakan kelas MTForecastClient
dalam proyek kita. Ini berarti hanya satu contoh dari kelas yang hidup pada satu waktu untuk seumur hidup aplikasi. Kemungkinannya adalah bahwa Anda sudah akrab dengan pola tunggal karena merupakan pola umum dalam banyak bahasa pemrograman berorientasi objek. Pada pandangan pertama, pola tunggal tampaknya sangat nyaman, tetapi ada sejumlah peringatan yang harus diwaspadai. Anda dapat mempelajari lebih lanjut tentang lajang dengan membaca artikel yang sangat bagus ini oleh Matt Gallagher.
Membuat objek tunggal cukup mudah dalam Objective-C. Mulai dengan mendeklarasikan metode kelas di MTForecastClient.h untuk menyediakan akses publik ke objek tunggal (lihat di bawah).
#import "AFHTTPClient.h" @interface MTForecastClient : AFHTTPClient #pragma mark - #pragma mark Shared Client + (MTForecastClient *)sharedClient; @end
Implementasi sharedClient
mungkin terlihat menakutkan pada awalnya, tetapi tidak begitu sulit begitu Anda memahami apa yang sedang terjadi. Kita pertama menyatakan dua variabel statis, (1) predicate
tipe dispatch_once_t
dan (2) _sharedClient
tipe MTForecastClient
. Seperti namanya, predicate
adalah predikat yang kita gunakan dalam kombinasi dengan fungsi dispatch_once
. Ketika bekerja dengan variabel jenis dispatch_once_t
, penting bahwa itu dinyatakan secara statis. Variabel kedua, _sharedClient
, akan menyimpan referensi ke objek tunggal.
Fungsi dispatch_once
mengambil pointer ke struktur dispatch_once_t
, predikat, dan blok. Keindahan dispatch_once
adalah bahwa ia akan mengeksekusi blok sekali untuk seumur hidup aplikasi, yang persis seperti yang kita inginkan. Fungsi dispatch_once
tidak memiliki banyak kegunaan, tetapi ini jelas salah satunya. Di blok yang kita lewati ke dispatch_once
, kita membuat objek tunggal dan menyimpan referensi di _sharedClient
. Lebih aman untuk meminta alloc
dan init
secara terpisah untuk menghindari kondisi balapan yang berpotensi menyebabkan kebuntuan. Euh ... apa? Anda dapat membaca lebih lanjut tentang detail sepele pada Stack Overflow.
+ (MTForecastClient *)sharedClient { static dispatch_once_t predicate; static MTForecastClient *_sharedClient = nil; dispatch_once(&predicate, ^{ _sharedClient = [self alloc]; _sharedClient = [_sharedClient initWithBaseURL:[self baseURL]]; }); return _sharedClient; }
Hal yang penting untuk dipahami tentang implementasi metode sharedClient
class adalah bahwa initializer, initWithBaseURL:
, hanya dipanggil sekali. Objek tunggal disimpan dalam variabel statis _sharedClient
, yang dikembalikan oleh metode kelas sharedClient
.
Langkah 3: Mengkonfigurasi Klien
Di sharedClient
, kita memanggil initWithBaseURL:
, yang pada gilirannya akan memanggil baseURL
, metode kelas lain. Di initWithBaseURL:
, kita menetapkan header default, yang berarti bahwa klien menambahkan header ini ke setiap permintaan yang dikirimkannya. Ini adalah salah satu keuntungan bekerja dengan kelas AFHTTPClient
. Di initWithBaseURL:
, kita juga mendaftarkan kelas operasi HTTP dengan menjalankan registerHTTPOperationClass:
. Perpustakaan AFNetworking menyediakan sejumlah kelas operasi khusus. Salah satu kelas ini adalah kelas AFJSONRequestOperation
, yang membuat berinteraksi dengan JSON API sangat mudah. Karena API Prakiraan mengembalikan respons JSON, kelas AFJSONRequestOperation
adalah pilihan yang baik. Metode registerHTTPOperationClass:
berfungsi mirip dengan bagaimana registerClass:forCellReuseIdentifier:
dari kelas UITableView
berfungsi. Dengan memberi tahu klien kelas operasi apa yang ingin kita gunakan untuk berinteraksi dengan layanan web, itu akan memberi contoh instance kelas itu untuk kita di bawah kap. Mengapa ini berguna akan menjadi jelas dalam beberapa saat.
- (id)initWithBaseURL:(NSURL *)url { self = [super initWithBaseURL:url]; if (self) { // Accept HTTP Header [self setDefaultHeader:@"Accept" value:@"application/json"]; // Register HTTP Operation Class [self registerHTTPOperationClass:[AFJSONRequestOperation class]]; } return self; }
Implementasi baseURL
tidak lebih dari metode kenyamanan untuk membangun basis URL klien. URL dasar adalah URL yang digunakan klien untuk menjangkau layanan web. Ini adalah URL tanpa nama atau parameter metode apa pun. URL dasar untuk Forecast API adalah https://api.forecast.io/forecast/
/. Kunci API adalah bagian dari URL seperti yang Anda lihat. Ini mungkin tampak tidak aman dan sebenarnya. Tidak sulit bagi seseorang untuk mengambil kunci API sehingga disarankan untuk bekerja dengan proxy untuk menutupi kunci API. Karena pendekatan ini sedikit lebih terlibat, saya tidak akan membahas aspek ini dalam seri ini.
+ (NSURL *)baseURL { return [NSURL URLWithString:[NSString stringWithFormat:@"https://api.forecast.io/forecast/%@/", MTForecastAPIKey]]; }
Anda mungkin telah memperhatikan dalam penerapan baseURL
bahwa saya telah menggunakan string konstan lainnya untuk menyimpan kunci API. Ini mungkin tampak tidak perlu karena kami hanya menggunakan kunci API di satu lokasi. Namun, ini adalah praktik yang baik untuk menyimpan data aplikasi di satu lokasi atau di daftar properti.
#pragma mark - #pragma mark Forecast API extern NSString * const MTForecastAPIKey;
#pragma mark - #pragma mark Forecast API NSString * const MTForecastAPIKey = @"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
Langkah 4: Menambahkan Metode Helper
Sebelum melanjutkan, saya ingin memperluas kelas MTForecastClient
dengan menambahkan metode helper atau kenyamanan yang akan memudahkan untuk kueri API Perkiraan. Metode kenyamanan ini akan menerima lokasi dan blok penyelesaian. Blok penyelesaian dijalankan ketika permintaan selesai. Agar lebih mudah bekerja dengan balok, sebaiknya deklarasikan jenis blok khusus seperti yang ditunjukkan di bawah ini. Jika Anda masih merasa tidak nyaman menggunakan blok, maka saya sarankan membaca artikel bagus ini oleh Akiel Khan.
Blok membutuhkan dua argumen, (1) boolean yang menunjukkan apakah kueri berhasil dan (2) kamus dengan respons dari kueri. Metode kenyamanan, requestWeatherForCoordinate:completion:
, mengambil koordinat lokasi (CLLocationCoordinate2D
) dan blok penyelesaian. Dengan menggunakan blok penyelesaian, kita dapat menghindari membuat protokol delegasi khusus atau mundur menggunakan pemberitahuan. Blok sangat cocok untuk jenis skenario ini.
#import "AFHTTPClient.h" typedef void (^MTForecastClientCompletionBlock)(BOOL success, NSDictionary *response); @interface MTForecastClient : AFHTTPClient #pragma mark - #pragma mark Shared Client + (MTForecastClient *)sharedClient; #pragma mark - #pragma mark Instance Methods - (void)requestWeatherForCoordinate:(CLLocationCoordinate2D)coordinate completion:(MTForecastClientCompletionBlock)completion; @end
Dalam
requestWeatherForCoordinate:completion:
, kita memanggil getPath:success:failure:
, metode yang dideklarasikan di AFHTTPClient
. Argumen pertama adalah jalur yang ditambahkan ke URL dasar yang kita buat sebelumnya. Argumen kedua dan ketiga adalah blok yang dieksekusi ketika permintaan berhasil dan gagal, masing-masing. Blok keberhasilan dan kegagalan cukup sederhana. Jika blok penyelesaian dilewatkan ke requestWeatherForCoordinate:completion:
, kita mengeksekusi blok dan meneruskan nilai boolean dan kamus respons (atau nil
pada blok kegagalan). Di blok kegagalan,kita mencatat kesalahan dari blok kegagalan ke konsol untuk memfasilitasi debugging.
- (void)requestWeatherForCoordinate:(CLLocationCoordinate2D)coordinate completion:(MTForecastClientCompletionBlock)completion { NSString *path = [NSString stringWithFormat:@"%f,%f", coordinate.latitude, coordinate.longitude]; [self getPath:path parameters:nil success:^(AFHTTPRequestOperation *operation, id response) { if (completion) { completion(YES, response); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { if (completion) { completion(NO, nil); NSLog(@"Unable to fetch weather data due to error %@ with user info %@.", error, error.userInfo); } }]; }
Anda mungkin bertanya-tanya apa objek response
dalam blok keberhasilan atau referensi. Meskipun API Forecast mengembalikan respons JSON, objek response
di blok sukses adalah instance NSDictionary
. Manfaat bekerja dengan kelas AFJSONHTTPRequestOperation
, yang kita daftarkan di initWithBaseURL:
, adalah bahwa ia menerima respons JSON dan secara otomatis membuat objek dari data respons, kamus dalam contoh ini.
2. Meminta Perkiraan API
Langkah 1: Ubah setLocation:
Berbekal kelas MTForecastClient
, sekarang waktunya untuk melakukan kueri API Prakiraan dan mengambil data cuaca untuk lokasi yang saat ini dipilih. Tempat yang paling cocok untuk melakukan ini adalah di setLocation:
metode kelas MTWeatherViewController
. Ubah metode setLocation:
seperti yang ditunjukkan di bawah ini. Seperti yang Anda lihat, semua yang kita lakukan adalah memohon fetchWeatherData
, metode pembantu lain.
- (void)setLocation:(NSDictionary *)location { if (_location != location) { _location = location; // Update User Defaults NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; [ud setObject:location forKey:MTRainUserDefaultsLocation]; [ud synchronize]; // Post Notification NSNotification *notification1 = [NSNotification notificationWithName:MTRainLocationDidChangeNotification object:self userInfo:location]; [[NSNotificationCenter defaultCenter] postNotification:notification1]; // Update View [self updateView]; // Request Location [self fetchWeatherData]; } }
Pernahkah Anda bertanya-tanya mengapa saya menggunakan begitu banyak metode helper dalam kode saya? Alasannya sederhana. Dengan membungkus fungsionalitas dalam metode pembantu, sangat mudah untuk menggunakan kembali kode di berbagai tempat proyek. Manfaat utama, bagaimanapun, adalah membantu memerangi duplikasi kode. Duplikasi kode adalah sesuatu yang harus selalu Anda hindari semaksimal mungkin. Keuntungan lain menggunakan metode helper adalah membuat kode Anda jauh lebih mudah dibaca. Dengan membuat metode yang melakukan satu hal dan memberikan nama metode yang dipilih dengan baik, lebih mudah untuk cepat membaca dan memproses kode Anda.
Langkah 2: Mengirim Permintaan
Saatnya menempatkan perpustakaan SVProgressHUD
untuk digunakan. Saya sangat suka perpustakaan ini karena sangat mudah digunakan tanpa mengacaukan basis kode proyek. Lihatlah implementasi fetchWeatherData
di bawah ini. Kita mulai dengan menunjukkan kemajuan HUD dan kemudian melewati sebuah struktur (CLLocationCoordinate2D
) ke metode kenyamanan yang kami buat sebelumnya, requestWeatherForCoordinate:completion:
. Di blok penyelesaian, kita menyembunyikan kemajuan HUD dan mencatat respons ke konsol.
- (void)fetchWeatherData { // Show Progress HUD [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient]; // Query Forecast API double lat = [[_location objectForKey:MTLocationKeyLatitude] doubleValue]; double lng = [[_location objectForKey:MTLocationKeyLongitude] doubleValue]; [[MTForecastClient sharedClient] requestWeatherForCoordinate:CLLocationCoordinate2DMake(lat, lng) completion:^(BOOL success, NSDictionary *response) { // Dismiss Progress HUD [SVProgressHUD dismiss]; NSLog(@"Response > %@", response); }]; }
Sebelum Anda membangun dan menjalankan aplikasi Anda, impor file header kelas MTForecastClient
di MTWeatherViewController.m.
#import "MTWeatherViewController.h" #import "MTForecastClient.h" @interface MTWeatherViewController () <CLLocationManagerDelegate> { BOOL _locationFound; } @property (strong, nonatomic) NSDictionary *location; @property (strong, nonatomic) CLLocationManager *locationManager; @end
Apa yang terjadi ketika perangkat tidak terhubung ke web? Sudahkah Anda memikirkan skenario itu? Dalam hal pengalaman pengguna, itu adalah praktik yang baik untuk memberi tahu pengguna ketika aplikasi tidak dapat meminta data dari API Forecast. Mari saya tunjukkan bagaimana melakukan ini dengan perpustakaan AFNetworking.
3. Jangkauan
Ada sejumlah perpustakaan yang menyediakan fungsionalitas ini, tetapi kita akan tetap dengan AFNetworking. Apple juga menyediakan kode contoh, tetapi agak ketinggalan jaman dan tidak mendukung ARC.
AFNetworking benar-benar memeluk blok, yang jelas merupakan salah satu alasan mengapa perpustakaan ini menjadi sangat populer. Pemantauan untuk perubahan reachability adalah sesederhana melewati blok ke setReachabilityStatusChangeBlock:
, metode lain dari kelas AFHTTPClient
. Blok ini dijalankan setiap kali status reachability berubah dan menerima satu argumen jenis AFNetworkReachabilityStatus
. Lihatlah initWithBaseURL;
yang diperbarui metode kelas MTForecastClient
.
- (id)initWithBaseURL:(NSURL *)url { self = [super initWithBaseURL:url]; if (self) { // Accept HTTP Header [self setDefaultHeader:@"Accept" value:@"application/json"]; // Register HTTP Operation Class [self registerHTTPOperationClass:[AFJSONRequestOperation class]]; // Reachability __weak typeof(self)weakSelf = self; [self setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { [[NSNotificationCenter defaultCenter] postNotificationName:MTRainReachabilityStatusDidChangeNotification object:weakSelf]; }]; } return self; }
Untuk menghindari siklus retensi, kita meneruskan referensi lemah ke objek tunggal di blok yang kita lewati ke setReachabilityStatusChangeBlock:
. Bahkan jika Anda menggunakan ARC dalam proyek Anda, Anda masih perlu menyadari masalah memori yang halus seperti ini. Nama pemberitahuan yang kita posting adalah string lain yang dinyatakan konstan di MTConstants.h /.m.
extern NSString * const MTRainReachabilityStatusDidChangeNotification;
NSString * const MTRainReachabilityStatusDidChangeNotification = @"com.mobileTuts.MTRainReachabilityStatusDidChangeNotification";
Alasan untuk memposting pemberitahuan dalam blok perubahan status reachability adalah untuk mempermudah bagian lain dari aplikasi untuk memperbarui ketika reachability perangkat berubah. Untuk memastikan bahwa kelas MTWeatherViewController
diberitahu tentang perubahan reachability, contoh kelas ditambahkan sebagai pengamat untuk pemberitahuan yang dikirim oleh klien Prakiraan seperti yang ditunjukkan di bawah ini.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Initialize Location Manager self.locationManager = [[CLLocationManager alloc] init]; // Configure Location Manager [self.locationManager setDelegate:self]; [self.locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer]; // Add Observer NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(reachabilityStatusDidChange:) name:MTRainReachabilityStatusDidChangeNotification object:nil]; } return self; }
Ini juga berarti bahwa kita perlu menghapus instance sebagai pengamat dalam metode dealloc
. Ini adalah detail yang sering diabaikan.
- (void)dealloc { // Remove Observer [[NSNotificationCenter defaultCenter] removeObserver:self]; }
Implementasi reachabilityStatusDidChange:
cukup mendasar saat ini. Kita akan memperbarui implementasinya setelah kita membuat antarmuka pengguna aplikasi.
- (void)reachabilityStatusDidChange:(NSNotification *)notification { MTForecastClient *forecastClient = [notification object]; NSLog(@"Reachability Status > %i", forecastClient.networkReachabilityStatus); }
4. Refreshing Data
Sebelum kita menyelesaikan posting ini, saya ingin menambahkan dua fitur tambahan, (1) mengambil data cuaca setiap kali aplikasi menjadi aktif dan (2) menambahkan kemampuan untuk menyegarkan data cuaca secara manual. Kita bisa mengimplementasikan timer yang mengambil data baru setiap jam atau lebih, tetapi ini tidak diperlukan untuk aplikasi cuaca menurut saya. Sebagian besar pengguna akan meluncurkan aplikasi, lihat cuaca dan letakkan aplikasi di background. Oleh karena itu hanya diperlukan untuk mengambil data baru ketika pengguna meluncurkan aplikasi. Ini berarti bahwa kita perlu mendengarkan pemberitahuan UIApplicationDidBecomeActiveNotification
di kelas MTWeatherViewController
. Seperti yang kita lakukan untuk memantau perubahan reachability, kita menambahkan instance kelas sebagai pengamat notifikasi tipe UIApplicationDidBecomeActiveNotification
.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { // Initialize Location Manager self.locationManager = [[CLLocationManager alloc] init]; // Configure Location Manager [self.locationManager setDelegate:self]; [self.locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer]; // Add Observer NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; [nc addObserver:self selector:@selector(reachabilityStatusDidChange:) name:MTRainReachabilityStatusDidChangeNotification object:nil]; } return self; }
Di applicationDidBecomeActive:
, kita memverifikasi bahwa location
sudah diatur (bukan nil
) karena ini tidak akan selalu benar. Jika lokasi valid, kita mengambil data cuaca.
- (void)applicationDidBecomeActive:(NSNotification *)notification { if (self.location) { [self fetchWeatherData]; } }
Saya juga telah mengubah fetchWeatherData
hanya untuk kueri API Prakiraan jika perangkat terhubung ke web.
- (void)fetchWeatherData { if ([[MTForecastClient sharedClient] networkReachabilityStatus] == AFNetworkReachabilityStatusNotReachable) return; // Show Progress HUD [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient]; // Query Forecast API double lat = [[_location objectForKey:MTLocationKeyLatitude] doubleValue]; double lng = [[_location objectForKey:MTLocationKeyLongitude] doubleValue]; [[MTForecastClient sharedClient] requestWeatherForCoordinate:CLLocationCoordinate2DMake(lat, lng) completion:^(BOOL success, NSDictionary *response) { // Dismiss Progress HUD [SVProgressHUD dismiss]; // NSLog(@"Response > %@", response); }]; }
Mari tambahkan tombol ke pengontrol tampilan cuaca yang dapat disentuh pengguna untuk menyegarkan data cuaca secara manual. Buat outlet di MTWeatherViewController.h dan buat refresh:
tindakan di MTWeatherViewController.m.
#import <UIKit/UIKit.h> #import "MTLocationsViewController.h" @interface MTWeatherViewController : UIViewController <MTLocationsViewControllerDelegate> @property (weak, nonatomic) IBOutlet UILabel *labelLocation; @property (weak, nonatomic) IBOutlet UIButton *buttonRefresh; @end
- (IBAction)refresh:(id)sender { if (self.location) { [self fetchWeatherData]; } }
Buka MTWeatherViewController.xib, tambahkan tombol ke tampilan pengontrol tampilan dengan judul Refresh, dan hubungkan outlet dan tindakan dengan tombol (gambar 3). Alasan untuk membuat stopkontak untuk tombol ini adalah untuk dapat menonaktifkannya ketika tidak ada koneksi jaringan tersedia. Agar ini berfungsi, kita perlu memperbarui metode reachabilityStatusDidChange:
seperti yang ditunjukkan di bawah ini.



- (void)reachabilityStatusDidChange:(NSNotification *)notification { MTForecastClient *forecastClient = [notification object]; NSLog(@"Reachability Status > %i", forecastClient.networkReachabilityStatus); // Update Refresh Button self.buttonRefresh.enabled = (forecastClient.networkReachabilityStatus != AFNetworkReachabilityStatusNotReachable); }
Tidak perlu untuk menonaktifkan sementara tombol refresh saat permintaan diproses di fetchWeatherData
karena kemajuan HUD menambahkan lapisan di atas tampilan pengontrol tampilan yang mencegah pengguna mengetuk tombol lebih dari satu kali. Bangun dan jalankan aplikasi untuk menguji semuanya.
Bonus: Menghapus Lokasi
Seorang pembaca bertanya kepada saya bagaimana menghapus lokasi dari daftar sehingga saya memasukkannya di sini demi kelengkapan. Hal pertama yang perlu kita lakukan adalah memberi tahu tampilan tabel baris mana yang dapat diedit dengan mengimplementasikan tableView:canEditRowAtIndexPath:
dari protokol UITableViewDataSource
. Metode ini mengembalikan YES
jika baris pada indexPath
dapat diedit dan NO
jika tidak. Implementasinya sederhana seperti yang Anda lihat di bawah ini. Setiap baris dapat diedit kecuali untuk baris pertama dan lokasi yang sedang dipilih.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) { return NO; } // Fetch Location NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)]; return ![self isCurrentLocation:location]; }
Untuk memeriksa apakah location
adalah lokasi saat ini, kita menggunakan metode pembantu lain, isCurrentLocation:
, di mana kita mengambil lokasi saat ini dan membandingkan koordinat lokasi. Akan lebih baik (dan lebih mudah) jika kita telah menetapkan pengenal unik untuk setiap lokasi yang disimpan dalam basis data default pengguna. Tidak hanya memudahkan untuk membandingkan lokasi, tetapi juga memungkinkan kita menyimpan pengidentifikasi unik lokasi saat ini di basis data default pengguna dan mencarinya di berbagai lokasi. Masalah dengan implementasi saat ini adalah lokasi dengan koordinat yang sama tidak dapat dibedakan satu sama lain.
- (BOOL)isCurrentLocation:(NSDictionary *)location { // Fetch Current Location NSDictionary *currentLocation = [[NSUserDefaults standardUserDefaults] objectForKey:MTRainUserDefaultsLocation]; if ([location[MTLocationKeyLatitude] doubleValue] == [currentLocation[MTLocationKeyLatitude] doubleValue] && [location[MTLocationKeyLongitude] doubleValue] == [currentLocation[MTLocationKeyLongitude] doubleValue]) { return YES; } return NO; }
Ketika pengguna mengetuk tombol hapus dari baris tampilan tabel, sumber data tampilan tabel dikirim tabelView:commitEditingStyle:forRowAtIndexPath:
pesan. Dalam metode ini, kita perlu (1) memperbarui sumber data, (2) menyimpan perubahan ke basis data default pengguna, dan (3) memperbarui tampilan tabel. Jika editingStyle
sama dengan UITableViewCellEditingStyleDelete
, kita menghapus lokasi dari larik location
dan menyimpan larik yang diperbarui di basis data default pengguna. Kita juga menghapus baris dari tampilan tabel untuk mencerminkan perubahan dalam sumber data.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { // Update Locations [self.locations removeObjectAtIndex:(indexPath.row - 1)]; // Update User Defaults [[NSUserDefaults standardUserDefaults] setObject:self.locations forKey:MTRainUserDefaultsLocations]; // Update Table View [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop]; } }
Untuk mengubah gaya pengeditan tabel tampilan, kita perlu menambahkan tombol edit ke antarmuka pengguna. Buat outlet untuk tombol di MTLocationsViewController.h dan tindakan bernama editLocations:
di MTLocationsViewController.m. Di editLocation:
, kita mengganti gaya pengeditan tabel tampilan.
#import <UIKit/UIKit.h> @protocol MTLocationsViewControllerDelegate; @interface MTLocationsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> @property (weak, nonatomic) id<MTLocationsViewControllerDelegate> delegate; @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (weak, nonatomic) IBOutlet UIBarButtonItem *editButton; @end @protocol MTLocationsViewControllerDelegate <NSObject> - (void)controllerShouldAddCurrentLocation:(MTLocationsViewController *)controller; - (void)controller:(MTLocationsViewController *)controller didSelectLocation:(NSDictionary *)location; @end
- (IBAction)editLocations:(id)sender { [self.tableView setEditing:![self.tableView isEditing] animated:YES]; }
Buka MTLocationsViewController.xib, tambahkan bilah navigasi ke tampilan pengontrol tampilan, dan tambahkan tombol edit ke bilah navigasi. Hubungkan tombol edit dengan outlet dan tindakan yang kami buat beberapa saat yang lalu.



Anda mungkin bertanya-tanya mengapa kita membuat outlet untuk tombol edit. Alasannya adalah bahwa kita harus dapat mengubah judul tombol edit dari Edit menjadi Done, dan sebaliknya, kapan saja gaya pengeditan dari tampilan tabel berubah. Selain itu, ketika pengguna menghapus lokasi terakhir (kecuali untuk lokasi saat ini) di tampilan tabel, alangkah baiknya untuk secara otomatis mengalihkan gaya pengeditan tabel tampilan. Fitur-fitur ini tidak sulit untuk diimplementasikan. Itulah mengapa saya membiarkannya sebagai latihan. Jika Anda mengalami masalah atau memiliki pertanyaan, jangan ragu untuk meninggalkan komentar di komentar di bawah artikel ini.
Kesimpulan
Kita telah berhasil mengintegrasikan API Prakiraan dalam aplikasi cuaca kita. Dalam tutorial berikutnya, kita akan menerapkan fokus pada antarmuka pengguna dan desain aplikasi.
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weekly