I am trying to present a camera view controller with a custom overlay containing two labels. I have been unable to get my imagePickerControllerDidCancel method and alertView to work properly. The system is printing the correct information to the NSLog but the lines of code that I have written are not doing anything and when the user taps 'Back' (to cancel the alertView and return to the imagePicker) the camera appears again but the takePhoto button and Cancel button are no longer accessible. They can still be seen but not tapped. When the user clicks the button at index 1 (Leave) I want the camera to be dismissed and to take the user back to my homeViewController which is at tabBarController index:1. In addition, when the camera first loads, the timerLabel is displayed with the correct data but then quickly disappears. I feel it has something to do with my refreshLabel method but again, I do not clearly understand where I am going wrong. None of these things are working for me and I'm still very new to the programming world so help with any of these matters would be greatly appreciated. thanks!
#import "CameraViewController.h"
#import "FriendsViewController.h"
#import <mobileCoreServices/UTCoreTypes.h>
#interface CameraViewController ()
#end
#implementation CameraViewController
#synthesize titleLabel;
#synthesize timerLabel;
- (void)viewDidLoad
{ [super viewDidLoad];
self.recipients = [[NSMutableArray alloc] init];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (self.image == nil && [self.videoFilePath length] == 0) {
self.imagePickerController = [[UIImagePickerController alloc] init];
self.imagePickerController.delegate = self;
self.imagePickerController.allowsEditing = NO;
self.imagePickerController.videoMaximumDuration = 10;
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
self.imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;}
self.imagePickerController.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:self.imagePickerController.sourceType];
[self presentViewController:self.imagePickerController animated:NO completion:nil];}
[[NSBundle mainBundle] loadNibNamed:#"OverlayView" owner:self options:nil];
self.overlayView.frame = CGRectMake(160,8,0,0);
self.imagePickerController.cameraOverlayView = self.overlayView;
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *deadline = [NSString stringWithFormat:#"%#/deadline.txt",
documentsDirectory];
NSString *name = [NSString stringWithFormat:#"%#/name.txt",
documentsDirectory];
NSError *fileError;
titleLabel.text = [NSString stringWithContentsOfFile:name
encoding:NSASCIIStringEncoding
error:&fileError];
timerLabel.text = [NSString stringWithContentsOfFile:deadline
encoding:NSASCIIStringEncoding
error:&fileError];
if(fileError.code == 0){
NSLog(#"deadline.txt was read successfully with these contents: %#,",
timerLabel.text);
NSLog(#"name.txt was read successfully with these contents: %#,",
titleLabel.text);}
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(refreshLabel)
userInfo:nil
repeats:YES];
}
-(void)refreshLabel;{
self.formatter = [NSDateFormatter new];
[self.formatter setDateFormat:#"dd:hh:mm:ss"];
NSDate *startDate = [self.formatter dateFromString:self.timerLabel.text];
NSDate *timeLeft = [startDate dateByAddingTimeInterval:-1];
NSTimeInterval totalCountdownInterval = -1;
NSTimeInterval elapsedTime = [timeLeft timeIntervalSinceNow];
NSTimeInterval remainingTime = totalCountdownInterval - elapsedTime;
if (remainingTime <= 0.0) {
//dismiss controller and set to homecontroller at tabBar index 1
}
self.timerLabel.text = [self.formatter stringFromDate:timeLeft];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Are you Sure?"
message:#"you can't come back"
delegate:self cancelButtonTitle:#"Back" otherButtonTitles:#"Yes", nil];
[alertView show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex==1) {
[self.imagePickerController dismissViewControllerAnimated:NO completion:nil];
[self.tabBarController setSelectedIndex:1];
NSLog(#"Leave clicked");
}
else {
[self reset];
NSLog(#"cancel clicked");
}
}
- (void)reset {
self.image = nil;
self.videoFilePath = nil;
}
Related
I am new to iOS. I have a UITextfield and a Keyword Search Button. When ever I want to search a keyword from a service and press enter. Tt should display the related searched keyword from a service. Please help me to fix this issue? TIA!
- (IBAction)KeywordSearchClicked:(id)sender {
NSMutableDictionary *dict=[[NSMutableDictionary alloc] init];
[self KeywordcallSignupProfileService:dict];
}
-(void)KeywordcallSignupProfileService:(NSMutableDictionary *)dict
{
[SVProgressHUD showWithStatus:#"" maskType:SVProgressHUDMaskTypeBlack]; // Progress
NSString * post = [[NSString alloc]initWithFormat:#"userId=%#&key_word%#",UserId,[dict objectForKey:#"key_word"]];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.amarbiyashaadi.com/service/amarbiya-service.svc/userKeywordSearch/"]];
RBConnect = [[RBConnection alloc]init];
RBConnect.delegate = self;
[RBConnect postRequestForUrl:url postBody:post];
}
#pragma mark - MRConnection Delegate Methods
- (void)jsonData:(NSDictionary *)jsonDict
{
[SVProgressHUD dismiss];
NSMutableArray *jsonArr;
NSMutableDictionary *userDict,*dict;
NSArray *arr=[jsonDict allKeys];
jsonArr=[jsonDict objectForKey:#"DataTable"];
if (jsonArr.count>0) {
// Save credentials in user defaults
matchesProfileArr=[jsonArr mutableCopy];
DisplayTableViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"DisplayTableViewController"];
[self presentViewController:vc animated:YES completion:nil];
}
else
{
NSString *error=#"Somthing Went Wrong";
[SVProgressHUD showErrorWithStatus:error];
}
}
I am programing an audio player using "AVFoundation.h". I've issues with Updating Progress bar, Hence when I click at play button my app gives error. I am attaching both code samples & error report. can anyone sort this out?
-(void)updateProgress {
NSInteger durationMinutes = [self.audioPlayer duration] / 60;
NSInteger durationSeconds = [self.audioPlayer duration] - durationMinutes * 60;
NSInteger currentTimeMinutes = [self.audioPlayer currentTime] / 60;
NSInteger currentTimeSeconds = [self.audioPlayer currentTime] - currentTimeMinutes * 60;
NSString *progressString = [NSString stringWithFormat:#"%d:%02d / %d:%02d", currentTimeMinutes, currentTimeSeconds, durationMinutes, durationSeconds];
self.timeLabel.text = progressString;
self.progressBar.progress = [self.audioPlayer currentTime] / [self.audioPlayer duration];
NSNumber *numCurrentTimeSeconds = [NSNumber numberWithInt:currentTimeSeconds];
NSNumber *numDurationSeconds = [NSNumber numberWithInt:durationSeconds];
NSString *songTitle = [self.selectedFilePath lastPathComponent];
NSString *artistName = #"MyPlayer";
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:#"placeholder"]];
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:#[songTitle, artistName, albumArt, numDurationSeconds, numCurrentTimeSeconds] forKeys:#[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork, MPMediaItemPropertyPlaybackDuration, MPNowPlayingInfoPropertyElapsedPlaybackTime]];
[infoCenter setNowPlayingInfo:infoDict]; }
When pressed Build & Run app goes successfully started in simulator, I've taken 2 images of active Console
1. before clicking at play button.
After clicking play button. when app goes crash.
enter image description here
now please suggest me what I should do at this point? so that my app start working smoothly...
Thanks
Faiz.
After following instructions by Losiowaty answer last day. those yellow issues are removed but still my programing gives same error when I click at play button.
enter image description here
This time I am uploading complete code and highlighting few things due to which I think error is occurring.
Please take a look at my mainwviewcontroller.m class code.
#interface MainViewController ()
#end
#implementation MainViewController
#synthesize audioPlayer;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
if (error == nil) {
NSLog(#"audio session initialized successfully");
} else {
NSLog(#"error initializing audio session: %#", [error description]);
}
[audioPlayer setDelegate:self];
MPVolumeView *volumeView = [ [MPVolumeView alloc] init] ;
[volumeView setFrame:self.airPlayView.bounds];
[self.airPlayView addSubview:volumeView];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(caughtInterruption:) name:AVAudioSessionInterruptionNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(routeChanged:) name:AVAudioSessionRouteChangeNotification object:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(BOOL)canBecomeFirstResponder
{
return YES;
}
-(void)dealloc
{
[self resignFirstResponder];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionInterruptionNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVAudioSessionRouteChangeNotification object:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showFilePicker"]) {
UINavigationController *navigationController = (UINavigationController *)segue.destinationViewController;
FileViewController *fileViewController = (FileViewController *)navigationController.topViewController;
fileViewController.delegate = self;
}
}
#pragma mark - file picker delegate methods
-(void)cancel
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)didFinishWithFile:(NSString *)filePath
{
NSError *error = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
self.selectedFilePath = filePath;
NSString *relativeFilePath = [documentsDirectory stringByAppendingPathComponent:filePath];
NSURL *fileURL = [NSURL fileURLWithPath:relativeFilePath];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
self.audioPlayer.delegate = self;
if (error == nil) {
NSLog(#"audio player initialized successfully");
self.titleLabel.text = self.selectedFilePath;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateProgress) userInfo:nil repeats:YES];
NSString *songTitle = [filePath lastPathComponent];
NSString *artistName = #"MyPlayer";
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:#"placeholder"]];
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:#[songTitle, artistName, albumArt] forKeys:#[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork]];
[infoCenter setNowPlayingInfo:infoDict];
[self play:nil];
} else {
NSLog(#"error initializing audio player: %#", [error description]);
}
//dismiss the file picker
[self dismissViewControllerAnimated:YES completion:nil];
}
-(IBAction)play:(id)sender
{
if ([self.audioPlayer isPlaying]) {
[self.audioPlayer pause];
[self.playButton setImage:[UIImage imageNamed:#"play"] forState:UIControlStateNormal];
[self.timer invalidate];
[animation stopAnimating];
} else {
[self.audioPlayer play];
[self.playButton setImage:[UIImage imageNamed:#"pause"] forState:UIControlStateNormal];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateProgress) userInfo:nil repeats:YES];
animation.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"animation1.png"],
[UIImage imageNamed:#"animation2.png"],
[UIImage imageNamed:#"animation3.png"],nil];
[animation setAnimationRepeatCount:2000];
animation.animationDuration = 0.5;
[animation startAnimating];
}
self.playbackInterrupted = NO;
}
-(IBAction)skipForward:(id)sender
{
if ([self.audioPlayer isPlaying]) {
NSTimeInterval desiredTime = self.audioPlayer.currentTime + 15.0f;
if (desiredTime < self.audioPlayer.duration) {
self.audioPlayer.currentTime = desiredTime;
}
}
}
-(IBAction)skipBackward:(id)sender
{
if ([self.audioPlayer isPlaying]) {
NSTimeInterval desiredTime = self.audioPlayer.currentTime - 15.0f;
if (desiredTime < 0) {
self.audioPlayer.currentTime = 0.0f;
} else {
self.audioPlayer.currentTime = desiredTime;
}
}
}
#pragma mark - Timer delegate
-(void)updateProgress
{
NSInteger durationMinutes = [self.audioPlayer duration] / 60;
NSInteger durationSeconds = [self.audioPlayer duration] - durationMinutes * 60;
NSInteger currentTimeMinutes = [self.audioPlayer currentTime] / 60;
NSInteger currentTimeSeconds = [self.audioPlayer currentTime] - currentTimeMinutes * 60;
NSString *progressString = [NSString stringWithFormat:#"%ld:%02ld / %ld:%02ld", currentTimeMinutes,currentTimeSeconds, durationMinutes, durationSeconds];
self.timeLabel.text = progressString;
self.progressBar.progress = [self.audioPlayer currentTime] / [self.audioPlayer duration];
NSNumber *numCurrentTimeSeconds = [NSNumber numberWithInteger:currentTimeSeconds];
NSNumber *numDurationSeconds = [NSNumber numberWithInteger:durationSeconds];
NSString *songTitle = [self.selectedFilePath lastPathComponent];
NSString *artistName = #"MyPlayer";
MPMediaItemArtwork *albumArt = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:#"placeholder"]];
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:#[songTitle, artistName, albumArt, numDurationSeconds, numCurrentTimeSeconds] forKeys:#[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork, MPMediaItemPropertyPlaybackDuration, MPNowPlayingInfoPropertyElapsedPlaybackTime]];
[infoCenter setNowPlayingInfo:infoDict];
}
#pragma mark - AVAudioPlayer delegate methods
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
if (flag) {
[self.playButton setImage:[UIImage imageNamed:#"play"] forState:UIControlStateNormal];
[self.timer invalidate];
[animation stopAnimating];
}
}
#pragma mark - Remote control
-(void)remoteControlReceivedWithEvent:(UIEvent *)event
{
switch (event.subtype) {
case UIEventSubtypeRemoteControlPlay:
case UIEventSubtypeRemoteControlPause:
case UIEventSubtypeRemoteControlTogglePlayPause:
[self play:nil];
break;
case UIEventSubtypeRemoteControlNextTrack:
[self skipForward:nil];
break;
case UIEventSubtypeRemoteControlPreviousTrack:
[self skipBackward:nil];
break;
default:
break;
}
}
#pragma mark - audio interruption
-(void)caughtInterruption:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
NSNumber *type =[userInfo objectForKey:AVAudioSessionInterruptionTypeKey];
if ([type integerValue] == AVAudioSessionInterruptionTypeBegan) {
if (self.audioPlayer.playing) {
[self.audioPlayer pause];
[animation stopAnimating];
self.playbackInterrupted = YES;
}
} else {
if (self.audioPlayer.playing == NO && self.playbackInterrupted == YES) {
[self.audioPlayer play];
[animation startAnimating];
self.playbackInterrupted = NO;
}
}
}
#pragma mark - route changed
-(void)routeChanged:(NSNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
NSNumber *reason =[userInfo objectForKey:AVAudioSessionRouteChangeReasonKey];
switch ([reason integerValue]) {
case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory:
[self.audioPlayer stop];
[animation stopAnimating];
break;
case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
case AVAudioSessionRouteChangeReasonWakeFromSleep:
[self.audioPlayer pause];
[animation stopAnimating];
break;
default:
break;
}
}
#end
above code is error free & pretty clean, everything is clearly mentioned, I am using 4 buttons,
for Play & Pause
for seeking forward
for seeking backward
for entering into document directory for audio file picking
when I am pressing this fourth button it prepares for entering into another view for picking audio file.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showFilePicker"]) {
UINavigationController *navigationController = (UINavigationController *)segue.destinationViewController;
FileViewController *fileViewController = (FileViewController *)navigationController.topViewController;
fileViewController.delegate = self;
}
}
I needs two things to accomplish
the first things which I needs to accomplish is that,
I don't wants to enter into next view, because I am testing my app into simulator where there is no physical audio file I can place or locate in simulator, hence I needs to avoid this thing just for my owns testing purpose.
Hence I am willing to add an audio mp3 file into NSBundle and wants to play this file when I press play button file starts playing & then Pause when pressing again. code for paying & pause is pretty clean working well. but for initializing file path is I think I've to initialize file path in viewDidload method by replacing above view did load by following code.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:#"Nameofflie" ofType:#"mp3"];
NSURL *pathAsURL = [[NSURL alloc] initFileURLWithPath:audioFilePath];
NSError *error = nil;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:pathAsURL error:&error];
if (error == nil) {
NSLog(#"audio session initialized successfully");
} else {
NSLog(#"error initializing audio session: %#", [error description]);
}
[audioPlayer setDelegate:self];
MPVolumeView *volumeView = [ [MPVolumeView alloc] init] ;
[volumeView setFrame:self.airPlayView.bounds];
[self.airPlayView addSubview:volumeView];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(caughtInterruption:) name:AVAudioSessionInterruptionNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(routeChanged:) name:AVAudioSessionRouteChangeNotification object:nil];
}
this code also Runs & compiles pretty well but when pressing play button same error occurring. so please suggest me where to place following lines to play MP3 Music file placed from NSBudle .
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:#"rabne" ofType:#"mp3"];
NSURL *pathAsURL = [[NSURL alloc] initFileURLWithPath:audioFilePath];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:pathAsURL error:&error];
this point is totally different from just above point number 1 which I am willing to accomplish. when after testing successfully, playing that NSBundle audio MP3 file.
I wants to work with my earlier code again, as the end user is not using my simulator, hence for end users I wants to have same option which already I accomplished in above Mainviewcontroller.m class,i.e. user have to press 4th number button for accessing their device's document directory file path. that works pretty well in my code. but the thing here I wants to point to or needs to sort out is that, if someone directly pressing very 1st play button without pressing 4th button for going & selecting an audio file, an alert view should appear with a message that first select a file by pressing fourth button and then click play button. That's it I am willing to have in my code.
Based on the exception in screenshot #2, it looks that you are trying to insert a nil object into an array. The only place where you insert some objects into array is this line :
NSDictionary *infoDict = [NSDictionary dictionaryWithObjects:#[songTitle, artistName, albumArt, numDurationSeconds, numCurrentTimeSeconds] forKeys:#[MPMediaItemPropertyTitle, MPMediaItemPropertyAlbumArtist, MPMediaItemPropertyArtwork, MPMediaItemPropertyPlaybackDuration, MPNowPlayingInfoPropertyElapsedPlaybackTime]];
The second array, the one with the keys, looks ok, as it consisits of only system provided consts. The first one on the other hand has two objects than could be nil : songTitle and albumArt.
The reasons for these to be nil are :
songTitle may be nil if self.selectedFilePath is nil
albumArt - I'm not entirely sure, but it could end up being nil if your image was not found.
Please make sure that these two are not nil and everything should be working fine.
As to your warnings, these two :
NSNumber *numCurrentTimeSeconds = [NSNumber numberWithInt:currentTimeSeconds];
NSNumber *numDurationSeconds = [NSNumber numberWithInt:durationSeconds];
can be fixed by changing to [NSNumber numberWithInteger:] and are caused by the fact that NSInteger is a typedef for long and not int.
The warning on
NSString *progressString = [NSString stringWithFormat:#"%d:%02d / %d:%02d", currentTimeMinutes, currentTimeSeconds, durationMinutes, durationSeconds];
is caused by virtually the same thing. %d expects an int, and NSInteger is a long. Changing %d to %ld will fix it.
It is still my firm belief that these didn't cause the crash, especially based on the thrown exception which is pretty straightforward in stating what has happend.
The provided code confirms my assumptions - the crash happens because self.selectedFilePath is nil in updateProgress method resulting in songTitle also being nil. Why this happens? The only place in provided code where you set self.selectedFilePath is in didFinishWithFile: method, which I assume is a delegate method of FileViewController. If you don't present it and selected something there, that method is not called.
Now, if you want to setup this for testing, the easiest way would be to add this in your viewDidLoad :
NSError *error;
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:#"rabne" ofType:#"mp3"];
NSURL *pathAsURL = [[NSURL alloc] initFileURLWithPath:audioFilePath];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:pathAsURL error:&error];
if (error == nil) {
self.selectedFilePath = #"test file"; // <<-- IMPORTANT
self.titleLabel.text = self.selectedFilePath;
} else {
NSLog(#"error initializing audio player: %#", [error description]);
}
just above [audioPlayer setDelegate:self];. This should get everything going.
On a side note : I'd also remove this line self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateProgress) userInfo:nil repeats:YES]; from didFinishWithFile: method - you also setup a timer in play: method, and it seems safer to do it once.
As to point #2 - I can give you a hint, that you know if a file is selected when self.selectedFilePath != nil and to take a look at UIAlertViewController class. The rest of work is left for you, as it was not a part of the original problem and has nothing to do with solving the crash. Also, you wouldn't learn anything that way :)
I am working on a iOS Application in which I have to add contacts in Address Book.
I want to open Edit Contact Screen Whenever user Tries to add duplicate contact.
But I don't know how to do that.Currently I am only able to show a message only.
I am getting all contacts list as:
NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBookRef);
Then I am itterating through it and check for existing one.If it exists then I am showing a message else I will add it to the addressbook.
for (id record in allContacts){
ABRecordRef thisContact = (__bridge ABRecordRef)record;
if (CFStringCompare(ABRecordCopyCompositeName(thisContact),
ABRecordCopyCompositeName(pet), 0) == kCFCompareEqualTo){
//The contact already exists!
NSLog(#"contact exosts");
}
else
{
ABAddressBookAddRecord(addressBookRef, pet, nil);
ABAddressBookSave(addressBookRef, nil);
ABMultiValueAddValueAndLabel(phoneNumbers, (__bridge CFStringRef)petPhoneNumber, kABPersonPhoneMainLabel, NULL);
NSLog(#"contacts Added");
}
}
How can I open following screen when user Tries to add duplicate contact:
I searched SO and find following questions but this doesn't help me.
Question 1
Question 2
And Is it possible to do so or not.Please any one assist me to achieve this feature if it is feasible.
See here .h
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
#interface ContactsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, ABPersonViewControllerDelegate>
{
IBOutlet UITableView *tblContacts;
NSMutableArray *arrContacts;
}
#end
And .m
#import "ContactsViewController.h"
#interface ContactsViewController ()
{
UIAlertController *action;
}
#end
#implementation ContactsViewController
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Contacts";
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addNewContact:)];
[self getContactsUsingAddressbook];
}
#pragma mark - Methods
// ------- Deprecated (in iOS 9.0) ----------
- (void)getContactsUsingAddressbook
{
ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus();
if (status == kABAuthorizationStatusDenied || status == kABAuthorizationStatusRestricted)
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:#"This app previously was refused permissions to contacts; Please go to settings and grant permission to this app so it can use contacts" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:nil]];
[self presentViewController:alert animated:TRUE completion:nil];
return;
}
CFErrorRef error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
if (!addressBook)
{
NSLog(#"ABAddressBookCreateWithOptions error: %#", CFBridgingRelease(error));
return;
}
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (error)
{
NSLog(#"ABAddressBookRequestAccessWithCompletion error: %#", CFBridgingRelease(error));
}
if (granted)
{
NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
arrContacts = [NSMutableArray arrayWithArray:allPeople];
[tblContacts reloadData];
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:nil message:#"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] show];
});
}
CFRelease(addressBook);
});
}
#pragma mark - Tableview delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arrContacts.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
//if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
cell.accessoryType = UITableViewCellAccessoryDetailButton;
// ------- Deprecated (in iOS 9.0) ----------
ABRecordRef person = (__bridge ABRecordRef)arrContacts[indexPath.row];
NSString *firstName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
NSString *lastName = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty));
cell.textLabel.text = [NSString stringWithFormat:#"%# %#", firstName, lastName];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// ------- Deprecated (in iOS 9.0) ----------
ABPersonViewController *personController = [[ABPersonViewController alloc] init];
personController.personViewDelegate = self;
personController.displayedPerson = (__bridge ABRecordRef)arrContacts[indexPath.row];
personController.allowsEditing = YES;
personController.allowsActions = YES;
[self.navigationController pushViewController:personController animated:TRUE];
}
#pragma mark - ABPersonview delegate
- (BOOL)personViewController:(ABPersonViewController *)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{
return TRUE;
}
And see in my simulator
You can edit contact as following
Here you have to add
// ------- Deprecated (in iOS 9.0)
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
ABPersonViewController *personController = [[ABPersonViewController alloc] init];
personController.personViewDelegate = self;
personController.displayedPerson = (__bridge ABRecordRef)arrContacts[indexPath.row];
personController.allowsEditing = YES;
personController.allowsActions = YES;
[self.navigationController pushViewController:personController animated:TRUE];
And here
#import <Contacts/Contacts.h>
#import <ContactsUI/ContactsUI.h>
// -------- This is not working for me, I got error
CNContact *contact = [arrContacts objectAtIndex:indexPath.row];
NSArray *keys = #[CNContactIdentifierKey, CNContactEmailAddressesKey, CNContactBirthdayKey, CNContactImageDataKey, CNContactPhoneNumbersKey, [CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]];
CNContactViewController *contactController = [CNContactViewController viewControllerForContact:contact];
contactController.delegate = self;
contactController.allowsEditing = YES;
contactController.allowsActions = YES;
contactController.displayedPropertyKeys = keys;
[self.navigationController pushViewController:contactController animated:TRUE];
See here Contact is missing some of the required key descriptors in ios
But still I have not found solution , If you have please tell me
Here is the answer
when bind arrayOfContact That time have to Provide key with [CNContactViewController descriptorForRequiredKeys].
NSArray *keys = #[CNContactGivenNameKey,CNContactFamilyNameKey,CNContactOrganizationNameKey, CNContactPhoneNumbersKey, CNContactEmailAddressesKey,CNContactPostalAddressesKey,[CNContactViewController descriptorForRequiredKeys]]
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:keys];
when open existing Contact
CNContactViewController *contactController = [CNContactViewController viewControllerForContact:contact];
contactController.delegate = self;
contactController.allowsEditing = YES;
contactController.allowsActions = YES;
[self.navigationController pushViewController:contactController animated:TRUE];
I have a button (Buy) to open up a UIView (viewInAppPurchases) on top of another UIView (viewMenu). The Buy button is in the UIView viewMenu. I also have a button (Close) in the UIView viewInAppPurchases.
In the code when clicking the close button in the viewInAppPurchases, it shall close the view and go back to the viewMenu. But when clicking on the Buy button again, nothing happens. It should reopen the viewInAppPurchases UIView.
What else should I add and/or change to the code so when the Buy button is clicked again, it shall open up the viewInAppPurchases again?
In Header file:
#property (strong, nonatomic) IBOutlet UIView *viewInAppPurchases;
In implementation .m file:
- (IBAction)buttonClose: (UIButton*)sender
{
[_viewInAppPurchases removeFromSuperview];
}
Below is the IAP as GaryRiches request. I noticed that I didn't have a "close button" instruction in the IAP itself, but only through the MenuViewController.
How do I put the close button instructions in it?
BuyView.h
#import <UIKit/UIKit.h>
#import <Social/Social.h>
#import "MyIAPHelper.h"
#interface BuyView : UIView
{
SKProduct *product;
NSMutableArray *lstProducts;
int productIndex;
BOOL hasProducts;
}
#property (nonatomic, strong) UIViewController *parentViewController;
- (IBAction)buyCoin:(id)sender;
- (IBAction)shareTwitterGetCoin:(id)sender;
- (IBAction)shareFacebookGetCoin:(id)sender;
#end
BuyView.m
#import "BuyView.h"
#implementation BuyView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(productPurchased:)
name:IAPHelperProductPurchasedNotification object:nil];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
NSArray *nibs = [[NSBundle mainBundle]
loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
// NSArray *subviewArray = [[NSBundle mainBundle]
loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
UIView *mainView = [nibs objectAtIndex:0];
//Just in case the size is different (you may or may not want this)
mainView.frame = self.bounds;
[self addSubview:mainView];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(productPurchased:)
name:IAPHelperProductPurchasedNotification object:nil];
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during
animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
- (IBAction)buyCoin:(id)sender {
BUTTON_SOUND
UIButton *btn = (UIButton *)sender;
NSString *productID = #"";
switch (btn.tag) {
case 0:
NSLog(#"buy 0.99");
productIndex = 0;
productID = FIRST_TIER;
break;
case 1:
NSLog(#"buy 1.99");
productIndex = 1;
productID = SECOND_TIER;
break;
case 2:
NSLog(#"buy 4.99");
productIndex = 2;
productID = THIRD_TIER;
break;
case 3:
NSLog(#"buy 9.99");
productIndex = 3;
productID = FOURTH_TIER;
break;
case 4:
NSLog(#"buy 19.99");
productIndex = 4;
productID = FIFTH_TIER;
break;
default:
break;
}
SKProduct *selectedProduct;
for (int i=0; i<lstProducts.count; i++) {
SKProduct *_product = [lstProducts objectAtIndex:i];
if ([_product.productIdentifier isEqualToString:productID]) {
selectedProduct = _product;
break;
}
}
[[MyIAPHelper shareInstance] buyProduct:selectedProduct];
}
- (void)productPurchased:(NSNotification *)notification {
NSLog(#"===========PurchaseViewController===========");
NSLog(#"purchased success");
//Add coin here IAPHelperProductPurchasedNotification
int increaCoin = 0;
switch (productIndex) {
case 0:
increaCoin = 100;
break;
case 1:
increaCoin = 250;
break;
case 2:
increaCoin = 750;
break;
case 3:
increaCoin = 2000;
break;
case 4:
increaCoin = 5000;
break;
default:
break;
}
NSString *strMsg = [NSString stringWithFormat:#"You have purchased
successfully and got %d coins",increaCoin];
UIAlertView *alert =[[UIAlertView alloc] initWithTitle:#"Message" message:strMsg delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
[self updateCoinWithIncreaseCoin:increaCoin];
}
- (void)updateCoinWithIncreaseCoin:(int)increaseCoin_{
int currentCoin = [Utils getCoin];
[Utils updateCoin:(currentCoin + increaseCoin_)];
}
- (IBAction)shareTwitterGetCoin:(id)sender {
BUTTON_SOUND
NSUserDefaults *userdefaults = [NSUserDefaults standardUserDefaults];
if (![userdefaults objectForKey:#"FIRST_SHARE_TWITTER"]) {
[userdefaults setObject:#"Abcd" forKey:#"FIRST_SHARE_TWITTER"];
[userdefaults synchronize];
SLComposeViewController *controller = [SLComposeViewController
composeViewControllerForServiceType:SLServiceTypeTwitter];
[controller setInitialText:#"Check out this new App!"];
[controller addURL:[NSURL URLWithString:APP_URL]];
[self.parentViewController presentViewController:controller
animated:YES completion:^{
//get coin here
NSLog(#"get coin share twitter");
int currentCoin = [Utils getCoin] + 30;
[Utils updateCoin:currentCoin];
}];
}
}
- (IBAction)shareFacebookGetCoin:(id)sender {
BUTTON_SOUND
NSUserDefaults *userdefaults = [NSUserDefaults standardUserDefaults];
if (![userdefaults objectForKey:#"FIRST_SHARE_FACEBOOK"]) {
[userdefaults setObject:#"Abc" forKey:#"FIRST_SHARE_FACEBOOK"];
[userdefaults synchronize];
SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];
[controller setInitialText:#"Check out this new App!"];
[controller addURL:[NSURL URLWithString:APP_URL]];
[self.parentViewController presentViewController:controller animated:YES completion:^{
//add coin here
NSLog(#"get coin share facebook");
int currentCoin = [Utils getCoin] + 30;
[Utils updateCoin:currentCoin];
}];
}else{
}
}
#end
What else should I add and/or change to the code so when the Buy
button is clicked again, it shall open up the viewInAppPurchases
again?
You should add it back to the view from which you removed it.
You can do it on click event by:
[self.view addSubview: _viewInAppPurchases];
Also, have you consider hiding it instead of removing it completly and then adding it back?
To hide your view:
[_viewInAppPurchases setHidden:YES];
To show it again:
[_viewInAppPurchases setHidden:NO];
I changed the
removeFromSuperview
to
setHidden:Yes
and it did the trick.
IOS Game
I am creating a game were there is a button and there aim of the game is see how much taps you can get before the time runs out
But i have a problem i need to recored the high score, how can i do that.
.h code
#import <UIKit/UIKit.h>
#interface errrViewController : UIViewController{
IBOutlet UILabel *label;
IBOutlet UILabel *timerLabel;
NSInteger count;
NSInteger seconds;
NSTimer *timer; //ADD THIS!!
}
- (IBAction) buttonPressed;
- (void)setupGame;
- (void)subtractTime;
#end
m. code
#import "errrViewController.h"
#interface errrViewController ()
#end
#implementation errrViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self setupGame];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//Implementing our method
- (IBAction)buttonPressed{
count++;
label.text = [NSString stringWithFormat:#"Score\n%i",count];
}
- (void)setupGame{
seconds = 30;
count = 0;
timerLabel.text = [NSString stringWithFormat:#"Time: %i",seconds];
label.text = [NSString stringWithFormat:#"Score\n%i",count];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(subtractTime) userInfo:nil repeats:YES];
}
- (void)subtractTime{
seconds--;
timerLabel.text = [NSString stringWithFormat:#"Time: %i",seconds];
if(seconds == 0){
[timer invalidate];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Time is up!" message:[NSString stringWithFormat:#"You scored %i points",count] delegate:self cancelButtonTitle:#"Play Again" otherButtonTitles:nil];
[alert show];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
[self setupGame];
}
#end
#import "errrViewController.h"
#interface errrViewController ()
#end
#implementation errrViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self setupGame];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//Implementing our method
- (IBAction)buttonPressed{
count++;
label.text = [NSString stringWithFormat:#"Score\n%i",count];
}
- (void)setupGame{
seconds = 30;
count = 0;
timerLabel.text = [NSString stringWithFormat:#"Time: %i",seconds];
label.text = [NSString stringWithFormat:#"Score\n%i",count];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(subtractTime) userInfo:nil repeats:YES];
}
- (void)subtractTime{
seconds--;
timerLabel.text = [NSString stringWithFormat:#"Time: %i",seconds];
if(seconds == 0){
[timer invalidate];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Time is up!" message:[NSString stringWithFormat:#"You scored %i points",count] delegate:self cancelButtonTitle:#"Play Again" otherButtonTitles:nil];
[alert show];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
[self setupGame];
}
#end
Please explain how to do this in steps
Please provide any links if possible that can help me
You can do this by saving the highscore to a plist file, in the form of a NSDictionary. For example:
int highscore; //your highscore variable, which I believe you can calculate yourself
Then you can have a save function like:
-(void) saveHighscore{
NSDictionary* highscoreDict = [[NSDictionary alloc] initWithObjectsAndKeys: [NSString stringWithFormat:#"%d", highscore], #"Highscore",nil];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
//get the path for the documents directory
NSString* filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent: #"Highscore.plist"];
//Check if file exists
if([[NSFileManager defaultManager]fileExistsAtPath:filePath]){
//delete it if it does, because we're going to replace it anyway
[[NSFileManager defaultManager]removeItemAtPath:filePath error:nil];
}
[highscoreDict writeToFile:filePath atomically:YES]; // write to file
}
And you can have a load highscore function like:
-(int) loadHighscore{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent: #"Highscore.plist"];
//Check if file exists
if([[NSFileManager defaultManager]fileExistsAtPath:filePath]){
NSDictionary* highscoreDict = [NSDictionary dictionaryWithContentsOfFile:filePath];
//Retrieve the value of highscore from your file
return [[highscoreDict valueForKey: #"Highscore"]intValue];
}
//Otherwise return 0 as the highscore
return 0;
}
And add [self loadHighscore]; in your viewDidLoad function.
Hope this helps.