I am using this code for apple maps integration.
CLLocationCoordinate2D rdOfficeLocation ;
//Apple Maps, using the MKMapItem class
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:rdOfficeLocation addressDictionary:nil];
MKMapItem *item = [[MKMapItem alloc] initWithPlacemark:placemark];
// NSLog(#"val is %#",placemark);
//item.name = #"ReignDesign Office";
[item openInMapsWithLaunchOptions:nil];
The above code is put in viewDidLoad method its come like this.
But I want user to enter the location in search bar that address is showing then how to fetch the address in NSLOG
If we want select the location by using hand gestures how to get that address location and lat,longitude values.
If anyone knows that process please let me know.
map image
you have to use google place search API for your need.
First you have to get API key from google developer console.
and the use below URL for get search places
https://maps.googleapis.com/maps/api/place/autocomplete/json?input=Vict&types=geocode&language=fr&key=YOUR_API_KEY
Download Library From Github
Step-1) first add class #class SPGooglePlacesAutocompleteQuery; before the #interface class in your viewController.h>>>>>>
#import <UIKit/UIKit.h>
#class SPGooglePlacesAutocompleteQuery;
#interface ViewController : UIViewController
{
SPGooglePlacesAutocompleteQuery *searchQuery;
}
#property (nonatomic,strong) NSMutableArray *mutArrSearchData;
#end
then your viewDidLoad >>>
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.mutArrSearchData = [NSMutableArray array];
searchQuery = [[SPGooglePlacesAutocompleteQuery alloc] init];
self.mutArrSearchData = [NSMutableArray array];
}
step-2) then if you are using UISearchBar then set delegate and add Delegate Methods. For EX:
- (void)searchBar:(UISearchBar *)searchBar
textDidChange:(NSString *)searchText{
if (searchBar.text.length>=1) {
[self handleSearchForSearchString:sender.text];
}
}
- (void)handleSearchForSearchString:(NSString *)searchString {
[self.mutArrSearchData removeAllObjects];
searchQuery.location = self.mapView.userLocation.coordinate;
searchQuery.input = searchString;
[searchQuery fetchPlaces:^(NSArray *places, NSError *error) {
if (error) {
SPPresentAlertViewWithErrorAndTitle(error, #"Could not fetch Places");
} else {
// you have got your related responce in this array
[self.mutArrSearchData addObjectsFromArray:places];
NSLog(#"responce:%#",self.mutArrSearchData);
//[self.tableview reloadData];
}
}];
}
you have got responce in up method. now you can parce this responce in your tableview. and didSelect Method....
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
yourCell *aCell;
[aCell.yourLbl.text setText:[self placeAtIndexPath:indexPath].name];
return aCell;
}
// Called after the user changes the selection.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
SPGooglePlacesAutocompletePlace *place = [self placeAtIndexPath:indexPath];
[place resolveToPlacemark:^(CLPlacemark *placemark, NSString *addressString, NSError *error) {
if (error) {
SPPresentAlertViewWithErrorAndTitle(error, #"Could not map selected Place");
} else if (placemark) {
// your selected placemark here. get data from placemark which you needed.
}
}];
}
- (SPGooglePlacesAutocompletePlace *)placeAtIndexPath:(NSIndexPath *)indexPath {
return [self.mutArrSearchData objectAtIndex:indexPath.row];
}
make sure to get API_KEY from google developer Console.
Hope it helps you.
Related
I'm trying to implement background fetch as well as refresh in iOS 10.
I'm using XML parsing to parse the data and then storing it in a file in the document's directory. For parsing XML I'm using a custom class (XMLParser) that confirms the NSXMLParserDelegate protocol.
The background fetch works fine. But I'm having problems in displaying the refreshed data, both when I click on the refresh button as well as in viewDidLoad.
I'm calling the refreshData method in viewDidLoad.
Here's how far I've gotten.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//--Set background fetch--//
[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
}
...
#pragma mark Background data fetch methods
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
NSDate *fetchStart = [NSDate date];
ArtsViewController *artsViewController = (ArtsViewController *)self.window.rootViewController;
[artsViewController fetchNewDataWithCompletionHandler:^(UIBackgroundFetchResult result) {
completionHandler(result);
NSDate *fetchEnd = [NSDate date];
NSTimeInterval timeElapsed = [fetchEnd timeIntervalSinceDate:fetchStart];
NSLog(#"Background Fetch Duration: %f seconds", timeElapsed);
}];
}
ArtsViewController.h
#interface ArtsViewController : UIViewController <UIPageViewControllerDataSource>
#property BOOL newsAvailable;
-(void)fetchNewDataWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler; // No problems here
#end
ArtsViewcontroller.m
#interface ArtsViewController ()
#property (nonatomic, strong) NSArray *arrNewsData;
-(void)refreshData;
-(void)performNewFetchedDataActionsWithDataArray:(NSArray *)dataArray;
#end
...
#implementation ArtsViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self refreshData];
//--Load the file that saves news--//
[self loadNews];
if (_newsAvailable == YES)
{
[self setupPageViewController];
}
else
{
[self showNoNewsMessage];
}
}
...
#pragma mark Data Fetch methods
-(void)refreshData{
XMLParser *xmlParser = [[XMLParser alloc] initWithXMLURLString:ArtsNewsFeed];
[xmlParser startParsingWithCompletionHandler:^(BOOL success, NSArray *dataArray, NSError *error) {
if (success) {
[self performNewFetchedDataActionsWithDataArray:dataArray];
}
else{
NSLog(#"%#", [error localizedDescription]);
}
}];
}
-(void)performNewFetchedDataActionsWithDataArray:(NSArray *)dataArray{
// 1. Initialize the arrNewsData array with the parsed data array.
if (self.arrNewsData != nil) {
self.arrNewsData = nil;
}
self.arrNewsData = [[NSArray alloc] initWithArray:dataArray];
// 2. Write the file and reload the view.
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * docDirectory = [paths objectAtIndex:0];
NSString * newsFilePath = [NSString stringWithFormat:#"%#",[docDirectory stringByAppendingPathComponent:#"arts2"]]; // NewsFile
if (![self.arrNewsData writeToFile:newsFilePath atomically:YES]) {
_newsAvailable = NO;
NSLog(#"Couldn't save data.");
}
else
{
_newsAvailable = YES;
NSLog(#"Saved data.");
[self viewWillAppear:YES];
}
}
-(void)fetchNewDataWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
XMLParser *xmlParser = [[XMLParser alloc] initWithXMLURLString:ArtsNewsFeed];
[xmlParser startParsingWithCompletionHandler:^(BOOL success, NSArray *dataArray, NSError *error) {
if (success) {
NSDictionary *latestDataDict = [dataArray objectAtIndex:0];
NSString *latestTitle = [latestDataDict objectForKey:#"title"];
NSDictionary *existingDataDict = [self.arrNewsData objectAtIndex:0];
NSString *existingTitle = [existingDataDict objectForKey:#"title"];
if ([latestTitle isEqualToString:existingTitle]) {
completionHandler(UIBackgroundFetchResultNoData);
NSLog(#"No new data found.");
}
else{
[self performNewFetchedDataActionsWithDataArray:dataArray];
completionHandler(UIBackgroundFetchResultNewData);
NSLog(#"New data was fetched.");
}
}
else{
completionHandler(UIBackgroundFetchResultFailed);
NSLog(#"Failed to fetch new data.");
}
}];
}
...
#pragma mark IBActions
- (IBAction)reloadNews:(UIBarButtonItem *)sender
{
[self viewDidLoad];
}
I've debugged the application and found that after viewDidLoad
completes execution, the data file is written but the view isn't
updated. I've also tried calling the refreshData method in the main
thread, but there's no change.
after viewDidLoad is complete the showNoNewNews method is called.
I'm suspecting that my logic isn't wrong but implementation is. Threads at play here..
Any help would be appreciated.
Update:
Hope this helps those with similar problems...
I moved the logic of viewDidLoad to a different method, called the method for the first time in viewDidLoad and again in refreshData, after
[self performNewFetchedDataActionsWithDataArray:dataArray];
I am integrating MoPub SDK to mediate ADs from the Google AdMob network. I can get the AD to show after implementing my own customEvent and Adapter, but i can't get the AD to handle click events on its own. As in when I click on the AdMob native AD, it won't direct me anywhere. When using Facebook and Flurry's CustomEvent and Adapter, clicks are handled automatically. Anyone have any experience on this subject?
Thanks in Advance. Code below:
MPGoogleAdMobCustomEvent
#interface MPGoogleAdMobCustomEvent()
#property(nonatomic, strong)GADAdLoader *loader;
#end
#implementation MPGoogleAdMobCustomEvent
- (void)requestAdWithCustomEventInfo:(NSDictionary *)info
{
MPLogInfo(#"MOPUB: requesting AdMob Native Ad");
NSString *adUnitID = [info objectForKey:#"adUnitID"];
if (!adUnitID) {
[self.delegate nativeCustomEvent:self didFailToLoadAdWithError:MPNativeAdNSErrorForInvalidAdServerResponse(#"MOPUB: No AdUnitID from GoogleAdMob")];
return;
}
self.loader = [[GADAdLoader alloc] initWithAdUnitID:adUnitID rootViewController:nil adTypes:#[kGADAdLoaderAdTypeNativeContent] options:nil];
self.loader.delegate = self;
GADRequest *request = [GADRequest request];
#if (TARGET_OS_SIMULATOR)
request.testDevices = #[ kGADSimulatorID ];
#endif
CLLocation *location = [[CLLocationManager alloc] init].location;
if (location) {
[request setLocationWithLatitude:location.coordinate.latitude
longitude:location.coordinate.longitude
accuracy:location.horizontalAccuracy];
}
request.requestAgent = #"MoPub";
[self.loader loadRequest:request];
}
- (void)adLoader:(GADAdLoader *)adLoader didReceiveNativeContentAd:(GADNativeContentAd *)nativeContentAd
{
MPLogDebug(#"MOPUB: Did receive nativeAd");
MPGoogleAdMobNativeAdAdapter *adapter = [[MPGoogleAdMobNativeAdAdapter alloc] initWithGADNativeContentAd:nativeContentAd];
adapter.url = nativeContentAd.advertiser;
MPNativeAd *interfaceAd = [[MPNativeAd alloc] initWithAdAdapter:adapter];
NSMutableArray *imageArray = [NSMutableArray array];
for (GADNativeAdImage *images in nativeContentAd.images) {
[imageArray addObject:images.imageURL];
}
[super precacheImagesWithURLs:imageArray completionBlock:^(NSArray *errors) {
if ([errors count]) {
[self.delegate nativeCustomEvent:self didFailToLoadAdWithError:errors[0]];
} else {
[self.delegate nativeCustomEvent:self didLoadAd:interfaceAd];
}
}];
}
- (void)adLoader:(GADAdLoader *)adLoader didFailToReceiveAdWithError:(GADRequestError *)error
{
MPLogDebug(#"MOPUB: AdMob ad failed to load with error (customEvent): %#", error.description);
[self.delegate nativeCustomEvent:self didFailToLoadAdWithError:error];
}
#end
MPGoogleAdMobNativeAdAdapter
#interface MPGoogleAdMobNativeAdAdapter()<GADNativeAdDelegate>
#property(nonatomic, strong)NSDictionary *properties;
#end
#implementation MPGoogleAdMobNativeAdAdapter
- (instancetype)initWithGADNativeContentAd:(GADNativeContentAd *)contentAD
{
self = [super init];
if (self) {
self.contentAd = contentAD;
self.contentAd.delegate = self;
self.properties = [self convertAssetsToProperties:contentAD];
}
return self;
}
- (NSDictionary *)convertAssetsToProperties:(GADNativeContentAd *)adNative
{
self.contentAd = adNative;
NSMutableDictionary * dictionary = [NSMutableDictionary dictionary];
if (adNative.headline) {
dictionary[kAdTitleKey] = adNative.headline;
}
if (adNative.body) {
dictionary[kAdTextKey] = adNative.body;
}
if (adNative.images[0]) {
dictionary[kAdMainImageKey] = ((GADNativeAdImage *)adNative.images[0]).imageURL.absoluteString;
}
if (adNative.callToAction) {
dictionary[kAdCTATextKey] = adNative.callToAction;
}
return [dictionary copy];
}
#pragma mark MPNativeAdAdapter
- (NSTimeInterval)requiredSecondsForImpression
{
return 0.0;
}
- (NSURL *)defaultActionURL
{
return nil;
}
- (BOOL)enableThirdPartyClickTracking
{
return YES;
}
- (void)willAttachToView:(UIView *)view
{
self.contentAd.rootViewController = [self.delegate viewControllerForPresentingModalView];
}
- (void)didDetachFromView:(UIView *)view
{
self.contentAd.rootViewController = nil;
}
#pragma mark GADNativeAdDelegate
- (void)nativeAdWillPresentScreen:(GADNativeAd *)nativeAd
{
if ([self.delegate respondsToSelector:#selector(nativeAdWillPresentModalForAdapter:)]) {
[self.delegate nativeAdWillPresentModalForAdapter:self];
}
}
- (void)nativeAdDidDismissScreen:(GADNativeAd *)nativeAd
{
if ([self.delegate respondsToSelector:#selector(nativeAdDidDismissModalForAdapter:)]) {
[self.delegate nativeAdDidDismissModalForAdapter:self];
}
}
- (void)nativeAdWillLeaveApplication:(GADNativeAd *)nativeAd
{
if ([self.delegate respondsToSelector:#selector(nativeAdWillLeaveApplicationFromAdapter:)]) {
[self.delegate nativeAdWillLeaveApplicationFromAdapter:self];
}
}
#end
`
If you are having your custom UI for AdMob Ad's, then there will be a button which you will be using for callToAction part.
First of all you need to add a selector to detect action of click, to do add the selector for that button
[callToActionButton addTarget:self action:#selector(adCalled:) forControlEvents:UIControlEventTouchUpInside];
After that implement the adCalled method to get the click & call the method further, below is the code for your reference
Below is the example which I have used to get the ad object from my collection view & then I am redirecting it.
- (void)adCalled:(id)sender
{
CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:mainCollectionView]; // Get the button position
NSIndexPath *indexPath = [collectionView indexPathForItemAtPoint:buttonPosition]; // Get the index path of button so that I can retrieve the correct ad object
id selectedAd = [adArray objectAtIndex:indexPath.row];
if ([selectedAd isKindOfClass:[GADNativeContentAd class]]) {
NSString *url = [selectedAd valueForKey:#"googleClickTrackingURLString"];
NSLog(#"URL is :%#", url);
NSURL *googleUrl = [NSURL URLWithString:url];
if ([[UIApplication sharedApplication] canOpenURL: googleUrl]) {
[[UIApplication sharedApplication] openURL:googleUrl];
}
}
}
Using this I can open the link n web using the google tracking url.
Hope this helps.
I am very new to programming. I have a rough knowledge base of c++ but objective-c is entirely new to me.
I'm trying to implement a simple UITableViewController in an app where the user is prompted to add email recipients from their contacts list. The TableViewController loads but not the TableViewCell data. I've been scouring the iOS developer library and I find the information very cookie-cutter like. I found their example code and copy/pasted it to my ViewController files. I made the necessary changes to conform to my files, deleted some unnecessary calls and followed every answer I've found on this site that remotely deals with my issue… To no avail! Here's what I have so far:
.h
#interface RecipientsViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource>
.m
#import "RecipientsViewController.h"
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
enum TableRowSelected
{
kUIDisplayPickerRow = 0,
kUICreateNewContactRow,
kUIDisplayContactRow,
kUIEditUnknownContactRow
};
// Height for the Edit Unknown Contact row
#define kUIEditUnknownContactRowHeight 81.0
#interface RecipientsViewController () < ABPeoplePickerNavigationControllerDelegate,ABPersonViewControllerDelegate,
ABNewPersonViewControllerDelegate, ABUnknownPersonViewControllerDelegate>
#property (nonatomic, assign) ABAddressBookRef addressBook;
#property (nonatomic, strong) NSMutableArray *menuArray;
#end
#implementation RecipientsViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
self.title = #"Recipients";
}
return self;
}
#pragma mark Load views
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
// Create an address book object
_addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
self.menuArray = [[NSMutableArray alloc] initWithCapacity:0];
[self checkAddressBookAccess];
[self.tableView reloadData];
}
#pragma mark -
#pragma mark Address Book Access
// Check the authorization status of our application for Address Book
-(void)checkAddressBookAccess
{
switch (ABAddressBookGetAuthorizationStatus())
{
// Update our UI if the user has granted access to their Contacts
case kABAuthorizationStatusAuthorized:
[self accessGrantedForAddressBook];
break;
// Prompt the user for access to Contacts if there is no definitive answer
case kABAuthorizationStatusNotDetermined :
[self requestAddressBookAccess];
break;
// Display a message if the user has denied or restricted access to Contacts
case kABAuthorizationStatusDenied:
case kABAuthorizationStatusRestricted:
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Privacy Warning"
message:#"Permission was not granted for Contacts."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
break;
default:
break;
}
}
// Prompt the user for access to their Address Book data
-(void)requestAddressBookAccess
{
RecipientsViewController * __weak weakSelf = self;
ABAddressBookRequestAccessWithCompletion(self.addressBook, ^(bool granted, CFErrorRef error)
{
if (granted)
{
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf accessGrantedForAddressBook];
});
}
});
}
// This method is called when the user has granted access to their address book data.
-(void)accessGrantedForAddressBook
{
// Load data from the plist file
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"Menu" ofType:#"plist"];
self.menuArray = [NSMutableArray arrayWithContentsOfFile:plistPath];
[self.tableView reloadData];
}
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [self.menuArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *aCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (aCell == nil)
{
// Make the Display Picker and Create New Contact rows look like buttons
if (indexPath.section < 2)
{
aCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
aCell.textLabel.textAlignment = NSTextAlignmentCenter;
}
else
{
aCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
aCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
aCell.detailTextLabel.numberOfLines = 0;
// Display descriptions for the Edit Unknown Contact and Display and Edit Contact rows
aCell.detailTextLabel.text = [[self.menuArray objectAtIndex:indexPath.section] valueForKey:#"description"];
}
}
// Configure the cell...
return aCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section)
{
case kUIDisplayPickerRow:
[self showPeoplePickerController];
break;
case kUICreateNewContactRow:
[self showNewPersonViewController];
break;
case kUIDisplayContactRow:
[self showPersonViewController];
break;
case kUIEditUnknownContactRow:
[self showUnknownPersonViewController];
break;
default:
[self showPeoplePickerController];
break;
}
}
#pragma mark TableViewDelegate method
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Change the height if Edit Unknown Contact is the row selected
return (indexPath.section==kUIEditUnknownContactRow) ? kUIEditUnknownContactRowHeight : tableView.rowHeight;
}
#pragma mark Show all contacts
// Called when users tap "Display Picker" in the application. Displays a list of contacts and allows users to select a contact from that list.
// The application only shows the phone, email, and birthdate information of the selected contact.
-(void)showPeoplePickerController
{
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
// Display only a person's phone, email, and birthdate
NSArray *displayedItems = [NSArray arrayWithObjects:[NSNumber numberWithInt:kABPersonPhoneProperty],
[NSNumber numberWithInt:kABPersonEmailProperty],
[NSNumber numberWithInt:kABPersonBirthdayProperty], nil];
picker.displayedProperties = displayedItems;
// Show the picker
[self presentViewController:picker animated:YES completion:nil];
}
#pragma mark Display and edit a person
// Called when users tap "Display and Edit Contact" in the application. Searches for a contact named "Appleseed" in
// in the address book. Displays and allows editing of all information associated with that contact if
// the search is successful. Shows an alert, otherwise.
-(void)showPersonViewController
{
// Search for the person named "Appleseed" in the address book
NSArray *people = (NSArray *)CFBridgingRelease(ABAddressBookCopyPeopleWithName(self.addressBook, CFSTR("Appleseed")));
// Display "Appleseed" information if found in the address book
if ((people != nil) && [people count])
{
ABRecordRef person = (__bridge ABRecordRef)[people objectAtIndex:0];
ABPersonViewController *picker = [[ABPersonViewController alloc] init];
picker.personViewDelegate = self;
picker.displayedPerson = person;
// Allow users to edit the person’s information
picker.allowsEditing = YES;
[self.navigationController pushViewController:picker animated:YES];
}
else
{
// Show an alert if "Appleseed" is not in Contacts
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Could not find Appleseed in the Contacts application"
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
[alert show];
}
}
#pragma mark Create a new person
// Called when users tap "Create New Contact" in the application. Allows users to create a new contact.
-(void)showNewPersonViewController
{
ABNewPersonViewController *picker = [[ABNewPersonViewController alloc] init];
picker.newPersonViewDelegate = self;
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController:picker];
[self presentViewController:navigation animated:YES completion:nil];
}
#pragma mark Add data to an existing person
// Called when users tap "Edit Unknown Contact" in the application.
-(void)showUnknownPersonViewController
{
ABRecordRef aContact = ABPersonCreate();
CFErrorRef anError = NULL;
ABMultiValueRef email = ABMultiValueCreateMutable(kABMultiStringPropertyType);
bool didAdd = ABMultiValueAddValueAndLabel(email, #"John-Appleseed#mac.com", kABOtherLabel, NULL);
if (didAdd == YES)
{
ABRecordSetValue(aContact, kABPersonEmailProperty, email, &anError);
if (anError == NULL)
{
ABUnknownPersonViewController *picker = [[ABUnknownPersonViewController alloc] init];
picker.unknownPersonViewDelegate = self;
picker.displayedPerson = aContact;
picker.allowsAddingToAddressBook = YES;
picker.allowsActions = YES;
picker.alternateName = #"John Appleseed";
picker.title = #"John Appleseed";
picker.message = #"Company, Inc";
[self.navigationController pushViewController:picker animated:YES];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Could not create unknown user"
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
[alert show];
}
}
CFRelease(email);
CFRelease(aContact);
}
#pragma mark ABPeoplePickerNavigationControllerDelegate methods
// Displays the information of a selected person
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
return YES;
}
// Does not allow users to perform default actions such as dialing a phone number, when they select a person property.
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{
return NO;
}
// Dismisses the people picker and shows the application when users tap Cancel.
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker;
{
[self dismissViewControllerAnimated:YES completion:NULL];
}
#pragma mark ABPersonViewControllerDelegate methods
// Does not allow users to perform default actions such as dialing a phone number, when they select a contact property.
- (BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person
property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue
{
return NO;
}
#pragma mark ABNewPersonViewControllerDelegate methods
// Dismisses the new-person view controller.
- (void)newPersonViewController:(ABNewPersonViewController *)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person
{
[self loadView];
}
#pragma mark ABUnknownPersonViewControllerDelegate methods
// Dismisses the picker when users are done creating a contact or adding the displayed person properties to an existing contact.
- (void)unknownPersonViewController:(ABUnknownPersonViewController *)unknownPersonView didResolveToPerson:(ABRecordRef)person
{
[self.navigationController popViewControllerAnimated:YES];
}
// Does not allow users to perform default actions such as emailing a contact, when they select a contact property.
- (BOOL)unknownPersonViewController:(ABUnknownPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{
return NO;
}
SORRY!!! Not sure which sections of code are most relevant to the problem.
* Given this much code is a little overwhelming for me to troubleshoot, I would greatly appreciate some help on this. I have no errors or issues showing up, the TableViewController loads. It only prompted the user to allow access to contacts a couple times and hasn't since. Even when the prompt did show, it never took me to the contacts on the simulator. I added contacts to the iOS simulator.
I sincerely appreciate any help!
I haven't gone through all of your code but the problem u described occurs with me mostly when my array is empty, try putting NSLog of your array contents at the places where you are adding objets to it,In order to see if its count is greater than 0.
What version of iOS are you using? That will determine if it will show up, if it is iOS 7 then you need permission to view the address book, thats the new thing they added.
This Link
https://developer.apple.com/library/ios/documentation/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/Chapters/QuickStart.html#//apple_ref/doc/uid/TP40007744-CH2-SW1
I cannot resolve this issue and I have no idea why my UITableView duplicates rows whenever I click on the segment control. I want to refresh the table view with new data when segment control changes. I have tried many things and googled it but could not find any solution. I would appreciated if someone can help me please. I am still learning xcode and a lot to learn. here is my code -
#import "citsViewController.h"
#import "citsParseOperation.h"
#import "citsFuelFinder.h"
#import "citsTableViewCell.h"
#import "citsAboutViewController.h"
#import "MBProgressHUD.h"
#import <CoreLocation/CoreLocation.h>
// this framework is imported so we can use the kCFURLErrorNotConnectedToInternet error code
#import <CFNetwork/CFNetwork.h>
#import <MapKit/MapKit.h>
#interface citsViewController ()
{
CLLocationManager *locationManager;
CLGeocoder *geocoder;
CLPlacemark *placemark;
NSString *currentLoc;
int productName;
}
#property (nonatomic) NSMutableArray *earthquakeList;
#property (nonatomic) citsFuelFinder *currentEarthquakeObject;
#property (nonatomic, weak) IBOutlet UILabel *locationLabel;
// queue that manages our NSOperation for parsing earthquake data
#property (nonatomic) NSOperationQueue *parseQueue;
#end
#pragma mark -
#implementation citsViewController
#synthesize nomatchesView;
#synthesize footerLabel;
#synthesize headerLabel;
#synthesize fuelType;
#synthesize bannerIsVisible;
- (void)viewDidLoad {
[super viewDidLoad];
//refresh the tableview
UIRefreshControl *refreshControl=[[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(refresh:) forControlEvents:UIControlEventValueChanged];
self.refreshControl=refreshControl;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
[infoButton addTarget:self action:#selector(aboutUs:) forControlEvents:UIControlEventTouchUpInside];
//add info button in the navigation controller
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:infoButton] ;
//initialize location manager
locationManager=[[CLLocationManager alloc] init];
//to get location
geocoder=[[CLGeocoder alloc] init];
//show network activity
[UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;
locationManager.delegate=self;
locationManager.desiredAccuracy=kCLLocationAccuracyBest;
//call the location manager update function
[locationManager startUpdatingLocation];
}
-(void)refresh:(id)sender {
//update table data
[locationManager startUpdatingLocation];
[self.refreshControl endRefreshing];
[self.tableView reloadData];
}
- (void)dealloc {
// we are no longer interested in these notifications:
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kAddEarthquakesNotificationName
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kEarthquakesErrorNotificationName
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSCurrentLocaleDidChangeNotification
object:nil];
}
/**
Handle errors in the download by showing an alert to the user. This is a very simple way of handling the error, partly because this application does not have any offline functionality for the user. Most real applications should handle the error in a less obtrusive way and provide offline functionality to the user.
*/
- (void)handleError:(NSError *)error {
NSString *errorMessage = [error localizedDescription];
NSString *alertTitle = NSLocalizedString(#"Error", #"Title for alert displayed when download or parse error occurs.");
NSString *okTitle = NSLocalizedString(#"OK ", #"OK Title for alert displayed when download or parse error occurs.");
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:alertTitle message:errorMessage delegate:nil cancelButtonTitle:okTitle otherButtonTitles:nil];
[alertView show];
}
/**
Our NSNotification callback from the running NSOperation to add the earthquakes
*/
- (void)addEarthquakes:(NSNotification *)notif {
assert([NSThread isMainThread]);
[self addEarthquakesToList:[[notif userInfo] valueForKey:kEarthquakeResultsKey]];
}
/**
Our NSNotification callback from the running NSOperation when a parsing error has occurred
*/
- (void)earthquakesError:(NSNotification *)notif {
assert([NSThread isMainThread]);
[self handleError:[[notif userInfo] valueForKey:kEarthquakesMessageErrorKey]];
}
/**
The NSOperation "ParseOperation" calls addEarthquakes: via NSNotification, on the main thread which in turn calls this method, with batches of parsed objects. The batch size is set via the kSizeOfFuelPumpBatch constant.
*/
- (void)addEarthquakesToList:(NSArray *)earthquakes {
NSInteger startingRow = [self.earthquakeList count];
NSInteger earthquakeCount = [earthquakes count];
NSMutableArray *indexPaths = [[NSMutableArray alloc] initWithCapacity:earthquakeCount];
for (NSInteger row = startingRow; row < (startingRow+earthquakeCount); row++) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
[indexPaths addObject:indexPath];
}
NSLog(#"record count %d",earthquakeCount);
[self.earthquakeList addObjectsFromArray:earthquakes];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
//[self.tableView reloadData];
}
#pragma mark - UITableViewDelegate
// The number of rows is equal to the number of earthquakes in the array.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.earthquakeList count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *kEarthquakeCellID = #"EarthquakeCellID";
citsTableViewCell *cell = (citsTableViewCell *)[tableView dequeueReusableCellWithIdentifier:kEarthquakeCellID];
if(cell==nil)
{
cell=[[citsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kEarthquakeCellID];
}
// Get the specific earthquake for this row.
citsFuelFinder *earthquake = (self.earthquakeList)[indexPath.row];
[cell configureWithEarthquake:earthquake];
return cell;
}
/**
* When the user taps a row in the table, display the USGS web page that displays details of the earthquake they selected.
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *buttonTitle = NSLocalizedString(#"Cancel", #"Cancel");
//NSString *buttonTitle1 = NSLocalizedString(#"Show USGS Site in Safari", #"Show USGS Site in Safari");
NSString *buttonTitle2 = NSLocalizedString(#"Show Location in Maps", #"Show Location in Maps");
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self
cancelButtonTitle:buttonTitle destructiveButtonTitle:nil
otherButtonTitles: buttonTitle2, nil];
[sheet showInView:self.view];
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.bounds.size.width, 500)];
headerLabel=[[UILabel alloc] initWithFrame:CGRectMake(10, 1.0, 300, 25)];
headerLabel.numberOfLines=0;
fuelType=[[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"ULP", #"PULP",#"Diesel",#"LPG", nil]];
fuelType.frame = CGRectMake(10, 30, 300,25);
//set first segment selected
[fuelType setSelectedSegmentIndex:0];
[fuelType addTarget:self action:#selector(segmentedControlHasChangedValue) forControlEvents:UIControlEventValueChanged];
headerLabel.font=[UIFont systemFontOfSize:10.0];
[headerView insertSubview:fuelType aboveSubview:headerLabel];
[headerView addSubview:headerLabel];
[headerView setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"footer.gif"]]];
return headerView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 60;
}
#pragma mark -
/**
* Called when the user selects an option in the sheet. The sheet will automatically be dismissed.
*/
- (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex {
NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
citsFuelFinder *earthquake = (citsFuelFinder *)(self.earthquakeList)[selectedIndexPath.row];
switch (buttonIndex) {
case 0: {
// open the earthquake info in Maps
// create a map region pointing to the earthquake location
CLLocationCoordinate2D location = (CLLocationCoordinate2D) { earthquake.latitude, earthquake.longitude };
NSValue *locationValue = [NSValue valueWithMKCoordinate:location];
MKCoordinateSpan span = (MKCoordinateSpan) { 2.0, 2.0 };
NSValue *spanValue = [NSValue valueWithMKCoordinateSpan:span];
NSDictionary *launchOptions = #{ MKLaunchOptionsMapTypeKey : #(MKMapTypeStandard),
MKLaunchOptionsMapCenterKey : locationValue,
MKLaunchOptionsMapSpanKey : spanValue,
MKLaunchOptionsShowsTrafficKey : #(NO),
MKLaunchOptionsDirectionsModeDriving : #(NO) };
// make sure the map item has a pin placed on it with the title as the earthquake location
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:location addressDictionary:nil];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:earthquake.location];
[mapItem openInMapsWithLaunchOptions:launchOptions];
break;
}
}
[self.tableView deselectRowAtIndexPath:selectedIndexPath animated:YES];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
// Regiser for HUD callbacks so we can remove it from the window at the right time
HUD.delegate = self;
HUD.labelText = #"Loading";
HUD.detailsLabelText = #"updating data";
HUD.square = YES;
self.earthquakeList = [NSMutableArray array];
self.currentEarthquakeObject=nil;
if([self.earthquakeList count] >0)
{
[self.earthquakeList removeAllObjects];
[self.tableView reloadData];
}
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(addEarthquakesToList:) onTarget:self withObject:nil animated:YES];
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
NSString *latitude=[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
NSString *longitude=[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
citsTableViewCell *tcell = [[citsTableViewCell alloc] init];
//set the latitude and longitude
tcell.lon =[longitude doubleValue];
tcell.lat = [latitude doubleValue];
NSLog(#"Lat:%#, Lon:%#", latitude,latitude);
}
//stop updating location
[locationManager stopUpdatingLocation];
//reverse geocoding
NSLog(#"Resolving the address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
currentLoc=[NSString stringWithFormat:#"%#",placemark.locality];
if(currentLoc == NULL)
{
currentLoc=#"N/A";
}
NSLog(#"%#",currentLoc);
//add text to headertext
NSDate *currDate=[NSDate date];
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yy HH:mm:ss"];
NSString *dateString=[dateFormatter stringFromDate:currDate];
NSString *loc=[NSString stringWithFormat:#"Your location: %#, Updated on: %#", currentLoc, dateString ];
[dateFormatter setDateFormat:#"EEEE, dd/MM/yyyy"];
NSString *headerDate=[dateFormatter stringFromDate:currDate];
headerLabel.text=[NSString stringWithFormat:#"Prices for: %#\n%#", headerDate,loc];
//currentLoc=[NSString stringWithFormat:#"%#", placemark.locality];
currentLoc=#"Mirrabooka";
if(productName==0)
{
productName=1;
}
NSString *prdStr=[[NSString alloc] initWithFormat:#"%d", productName];
NSString *str =[currentLoc stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
NSString *feedURLString =[[NSString alloc] initWithFormat: #"http://www.fuelwatch.wa.gov.au/fuelwatch/fuelWatchRSS?Product=%#&Suburb=%#", prdStr,str ];
NSURLRequest *earthquakeURLRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:feedURLString]];
NSLog(#"%#",feedURLString);
// send the async request (note that the completion block will be called on the main thread)
//
// note: using the block-based "sendAsynchronousRequest" is preferred, and useful for
// small data transfers that are likely to succeed. If you doing large data transfers,
// consider using the NSURLConnectionDelegate-based APIs.
//
[NSURLConnection sendAsynchronousRequest:earthquakeURLRequest queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
// back on the main thread, check for errors, if no errors start the parsing
//
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
// here we check for any returned NSError from the server, "and" we also check for any http response errors
if (error != nil) {
[self handleError:error];
}
else {
// check for any response errors
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ((([httpResponse statusCode]/100) == 2) ) {
// Update the UI and start parsing the data,
// Spawn an NSOperation to parse the earthquake data so that the UI is not
// blocked while the application parses the XML data.
//
citsParseOperation *parseOperation = [[citsParseOperation alloc] initWithData:data];
[self.parseQueue addOperation:parseOperation];
}
else {
NSString *errorString =
NSLocalizedString(#"HTTP Error", #"Error message displayed when receving a connection error.");
NSDictionary *userInfo = #{NSLocalizedDescriptionKey : errorString};
NSError *reportError = [NSError errorWithDomain:#"HTTP"
code:[httpResponse statusCode]
userInfo:userInfo];
[self handleError:reportError];
}
}
}];
// Start the status bar network activity indicator.
// We'll turn it off when the connection finishes or experiences an error.
//
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
self.parseQueue = [NSOperationQueue new];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(addEarthquakes:)
name:kAddEarthquakesNotificationName object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(earthquakesError:)
name:kEarthquakesErrorNotificationName object:nil];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
NSLog(#"%d",[self.earthquakeList count]);
}
-(void)clearData{
[self.tableView beginUpdates];
NSMutableArray *indexPathsToDelete = [[NSMutableArray alloc] init];
for (int i = [self.tableView numberOfRowsInSection:0] - 1; i >= 0; i--)
{
[indexPathsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:0]];
NSLog(#"Deleted: %d",i);
}
[self.tableView deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:UITableViewRowAnimationFade];
[self.earthquakeList removeAllObjects];
[self.tableView endUpdates];
//[self.tableView reloadData] ;
}
-(void)segmentedControlHasChangedValue{
int product;
product=fuelType.selectedSegmentIndex;
switch (product) {
case 0:
productName=1;
[locationManager startUpdatingLocation];
[self clearData];
break;
case 1:
productName=2;
[self clearData];
[locationManager startUpdatingLocation];
break;
case 2:
productName=4;
[self clearData];
[locationManager startUpdatingLocation];
break;
case 3:
prod![enter image description here][1]uctName=5;
[self clearData];
[locationManager startUpdatingLocation];
break;
}
NSLog(#"%d",productName);
return;
}
#end
Try removing all previous object from the self.earthquakeList before adding new 1. use [self.earthquakeList removeAllObjects]
Remove this Line,
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
And uncomment,
[self.tableView reloadData];
You are Already updating the data set, So you just need to reload the tableView instead of explicitly insert row.
I am quite new to Objective-C and this is the first time I have attempted to implement MVC. I have a model class where l have an NSArray which will be populated with data from a JSON object. I want to populate my UITableView (in my view controller class), with objects from this array.
Please review my code:
Droplets.h
#interface Droplets : NSObject {
NSArray *dropletsArray;
}
// Get droplets data
- (void) getDropletsList;
//Object initilization
- (id) init;
//Public properties
#property (strong, nonatomic) NSArray *dropletsArray; // Used to store the selected JSON data objects
#end
Droplets.m
#define kBgQueue dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define kDigialOceanApiURL [NSURL URLWithString:#"http://inspiredwd.com/api-test.php"] //Droplets API call
#import "Droplets.h"
#interface Droplets ()
//Private Properties
#property (strong, nonatomic) NSMutableData *data; // Used to store all JSON data objects
#end
#implementation Droplets;
#synthesize dropletsArray;
#synthesize data;
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (void) getDropletsList {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
NSURL *url = kDigialOceanApiURL; // Predefined Digital Ocean URL API http request
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection connectionWithRequest:request delegate:self]; //Should be: [[NSURLConnection alloc]initiWithRequest:request delegate:self]; ...however the instance of NSURLConnection is never used, which results in an "entity unsed" error.
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
data = [[NSMutableData alloc]init]; // mutable data dictionary is allocated and initilized
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData {
[data appendData:theData]; // append 'theData' to the mutable data dictionary
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
//JSON foundation object returns JSON data from a foundation object. Assigned returned data to a dictionary 'json'.
NSDictionary* jsonData = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions error:0];
self.dropletsArray = [jsonData objectForKey:#"droplets"]; //dictionary of arrays
NSLog(#"Droplets %#", self.dropletsArray);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// If the application is unable to connect to The Digital Ocean Server, then display an UIAlertView
UIAlertView *errorView = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Unable to connect to The Digital Ocean Server, please ensure that you are connected via either WIFI or 3G." delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[errorView show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO; // Turn of the network activity indicator
}
#end
DropletsList.h
#class Droplets;
#interface DropletsList : UITableViewController
- (Droplets *) modelDroplets;
#end
DropletsList.m
#define RGB(r, g, b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]
#interface DropletsList ()
//Private properties
#property (strong, nonatomic) Droplets *modelDroplets;
#property (strong, nonatomic) NSArray *tableData;
#end
#implementation DropletsList
#synthesize tableData;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
NSLog(#"get my data from model");
}
return self;
}
- (Droplets *) modelDroplets
{
if (!_modelDroplets) _modelDroplets = [[Droplets alloc]init];
return _modelDroplets;
}
- (void)viewDidLoad
{
[super viewDidLoad];
_modelDroplets = [[Droplets alloc]init];
self.tableData = [_modelDroplets dropletsArray];
[_modelDroplets getDropletsList];
[self.tableView reloadData]; // reload the droplets table controller
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView {
return 1; // Return the number of sections.
}
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {
return [_modelDroplets.dropletsArray count]; // Return the number of rows in the section.
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// The cell identified by "dropletsList", is assiged as the UITableViewCell
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"dropletsList"];
//NSLog(#"Droplets Name: %#",self.dropletsArray);
// The UITableView text label is assigned the contents from 'dropletsArray', with the object key "name"- name of the droplet
cell.textLabel.text=[[tableData objectAtIndex:indexPath.row]objectForKey:#"name"];
// The UITableView text detail label is assigned the contents from 'dropletsArray', with the object key "status"- status of the droplet
cell.detailTextLabel.text=[[tableData objectAtIndex:indexPath.row]objectForKey:#"status"];
//Evalulate the status of each droplet, setting the colour appropriate to the staus
if ([[[tableData objectAtIndex:indexPath.row] objectForKey:#"status"] isEqualToString:#"active"]) {
//Set the detail text label colour
cell.detailTextLabel.textColor = RGB (35,179,0);
}
return cell;
}
#end
Basically my table doesn't populate. Please could someone help?
- (void)viewDidLoad
{
[super viewDidLoad];
_modelDroplets = [[Droplets alloc]init];
self.tableData = [_modelDroplets dropletsArray];
[_modelDroplets getDropletsList];
[self.tableView reloadData]; // reload the droplets table controller
}
In this method you are fetching droplets from a webservice. It is asynchronous, by the time tableView reloads the data it might not have completed fetching the data. You need to have a callback which will reload the tableView on completion of webservice.
EDIT :
Create a class method in Droplets to fetch all data
//Droplets.h
typedef void (^NSArrayBlock)(NSArray * array);
typedef void (^NSErrorBlock)(NSError * error);
//Droplets.m
+ (void)getDropletsWithCompletion:(NSArrayBlock)arrayBlock onError:(NSErrorBlock)errorBlock
{
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:kDigialOceanApiURL];
[urlRequest setHTTPMethod:#"GET"];
[urlRequest setCachePolicy:NSURLCacheStorageNotAllowed];
[urlRequest setTimeoutInterval:30.0f];
[urlRequest addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[NSURLConnection sendAsynchronousRequest:urlRequest
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *responseData, NSError *error) {
if (error) {
errorBlock(error);
}else{
NSError *serializationError = nil;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData
options:NSJSONReadingAllowFragments
error:&serializationError];
arrayBlock(json[#"droplets"]);
}
}];
}
//DropletsList.h
- (void)viewDidLoad
{
[super viewDidLoad];
[Droplets getDropletsWithCompletion:^(NSArray *array) {
self.modelDroplets = droplets;
[self.tableView reloadData];
} onError:^(NSError *error) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Error" message:error.localizedDescription delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
}];
}
Disclaimer : Tested and verified :)