How do to use the tel:// scheme with stringWithFormat - objective-c

I am trying to create a simple phone book app that allows me to call people from the list. The app lists the names of the contacts and their phone numbers in different sections alphabetically based on the last name. Everything is displaying properly, my issue is when I select a contact and get prompted to "Cancel" or "Call", the "Call" button in the alertView doesn't do anything.
Here is the code I am using (urlString is a global variable):
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog("#didSelectRowAtIndexPath");
NSString *alphabet = [nameIndex objectAtIndex:[indexPath section]];
if([alphabet isEqual:#"A"])
{
UIAlertView *messageAlert = [[UIAlertView alloc] initWithTitle:#"Do you want to call.." message:[SectionA objectAtIndex:indexPath.row] delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Call", nil];
NSString *urlString = [NSString stringWithFormat:#"tel://%#",[SectionA objectAtIndex:indexPath.row]];
[messageAlert show];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
There are more if statements with the same code for the different sections of name/numbers, for the sake of space and time I just added the one section.
Here is where I attempt to make the "Call" button actually call the number:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex != [alertView cancelButtonIndex])
{
NSLog(#"Calling phone number");
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlString]];
}
}
The alert displays the proper phone number selected, and when I select "Call" nothing happens. But "Calling phone number" does show up in the output log. Stuck at the moment I'm assuming what I store in urlString isn't correct; or how I'm using urlString isn't correct. Any help would be appreciated, thanks!

Change this line
NSString *urlString = [NSString stringWithFormat:#"tel://%#",[SectionA objectAtIndex:indexPath.row]];
to this
urlString = [NSString stringWithFormat:#"tel://%#",[SectionA objectAtIndex:indexPath.row]];
You shadowed a local variable over a global / instance variable, hence the assigned value never reaches the point you expected. In other words, there are two urlString's existing at that point. A local one and one that is scoped globally / instance wide. Your assignment changed the local one, your attempt to use the value uses the global / instance one.

Related

Connect to peripheral in didSelectRowAtIndexPath

I am developing an app using CoreBluetooth. I am able to discover devices from the app and show their names in the table view. I am facing a problem with requirements below:
When used for the first time, the user selects a peripheral from the list. Connection should be established with the peripheral using the Bluetooth Serial Port Profile (SPP). Discovery and connection is simple and accomplished with a single click, minimizing user interaction.
Once a connection has been established between the peripheral device and the app, the app remembers the device and always seeks and connects to it for all subsequent uses.
I have written the following code for this as below for scanning and discovering
- (void)scan
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], CBCentralManagerScanOptionAllowDuplicatesKey, nil];
NSLog(#"options are %#",options);
[self.centralManager scanForPeripheralsWithServices:nil
options:nil];
_txtLogMessage.text = [NSString stringWithFormat:#"%# \n %#",_txtLogMessage.text,#"Scanning started"];
NSLog(#"Scanning started");
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral
*)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
[central connectPeripheral:peripheral options:nil];
self.discoveredPeripheral = peripheral;
_logData = [NSString stringWithFormat:#"Did discover peripheral. peripheral: %# rssi: %#, UUID: %# advertisementData: %# ", peripheral, RSSI, peripheral.UUID, advertisementData];
NSLog(#"%#",_logData);
[_periferalDevices addObject:peripheral.name];
[_tableView reloadData];
}
for connecting the device
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
peripheral.delegate = self;
[self.discoveredPeripheral discoverServices:nil];
NSLog(#"Peripheral Connected");
NSLog(#" started time is %#",_timestring);
//[self.centralManager stopScan];
NSLog(#"Scanning stopped");
[self.data setLength:0];
[peripheral discoverServices:nil];
[peripheral discoverServices:#[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];
}
in table view cell for row at index path aim able to get the data to view but aim facing problem in connecting to a peripheral while particular row is selected in the table view
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [_periferalDevices objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_discoveredPeripheral.delegate = self;
[self.centralManager connectPeripheral:[_periferalDevices objectAtIndex:indexPath.row]
options:nil];
NSLog(#"discovered peripheral is %#",[_periferalDevices objectAtIndex:indexPath.row]);
NSString *datstr=[_discoveredPeripheral valueForKey:#"identifier"];
NSLog(#"value for key is ........%#",datstr);
}
The errors that you get when you try to use the peripheral object stems from the fact that you added the name of the peripheral to your array rather than the peripheral, itself. Thus, replace
[_periferalDevices addObject:peripheral.name];
With
[_periferalDevices addObject:peripheral];
And, obviously, you'll have to fix wherever you took advantage of just inserting the name. For example, your cellForRowAtIndexPath bears a line that says:
cell.textLabel.text = [_periferalDevices objectAtIndex:indexPath.row];
You'd probably want to replace that with something like:
CBPeripheral *peripheral = _periferalDevices[indexPath.row];
cell.textLabel.text = peripheral.name;
Your didDiscover... is connecting immediately. It probably shouldn't. You should probably only try connecting to the device the user selected. This could cause problems if you try to connect again (I don't know what it does if you try to connect twice). Your didSelectRow... connects on the ones the user chooses, so you should probably leave it at that.
You say "am facing problem connecting". So, what precisely did didFailToConnectPeripheral report?
As an aside, I'm unclear why you're calling discoverServices twice, too. Either discover all services (slow) or discover just the particular service, but you probably don't have to do both.
My original answer (based upon original code sample) is below.
You have code that says:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellText = cell.textLabel.text;
if([cellText isEqualToString:#""])
{
}
else
{
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"Connected to "
message:cellText delegate:self cancelButtonTitle:#"ok"
otherButtonTitles: nil];
[alert show];
}
_discoveredPeripheral.delegate = self;
[self.centralManager connectPeripheral:_discoveredPeripheral options:nil];
NSLog(#"discovered peripheral is %#", _discoveredPeripheral);
NSString *datstr = [_discoveredPeripheral valueForKey:#"identifier"];
NSLog(#"value for key is ........%#", datstr);
}
You are retrieving the information on the selected cell (though Hot Licks is correct, you should be going to your model, not to the view for that information), retrieving the cellText, but you proceed to use _discoveredPeripheral, which is some variable that bears no obvious relation to the cell the user just selected.
You want to maintain your model of the array of peripherals, and when a user taps on the cell, use the indexPath.row to look up the peripheral in your model array, and use that CBPeripheral in your connection code.

Application having trouble when opening with network

I'm building an app that is using the Instagram API to display photos but I'm running into some trouble. The app is crashing when there is no network connection and I have found the code that is causing the problem.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
self.accessToken = [userDefaults objectForKey:#"accessToken"];
if (self.accessToken == nil) {
[SimpleAuth authorize:#"instagram" options:#{#"scope": #[#"likes"]} completion:^(NSDictionary *responseObject, NSError *error) {
self.accessToken = responseObject[#"credentials"][#"token"];
[userDefaults setObject:self.accessToken forKey:#"accessToken"];
[userDefaults synchronize];
[self refresh];
}];
} else {
[self refresh];
}
I have found that the [self refresh]; is causing the problem in the else block and I tried to replace it with a alert view like this
UIAlertView *networkError = [[UIAlertView alloc] initWithTitle:#"Network Error" message:#"Please connect your device to a network and restart application" delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
[networkError show];
However, with this problem I find that if I open the app with a network connection I still get the alert. Any help would be great because I'm still new to Objective C!
Thank you for the help!
I know this code from Treehouse :).
The thing is that the if (self.accessToken == nil) { /.../ } block will only get execute when the app is not authorized using your Instagram credentials.
Once you logged in successfully, it will always execute the code in the else { /.../ } block. If it has connection to Internet, it will do its work, download, display images etc. If you insert the code to display alert, it will always do that because you actually mean that by that code.
If you want to check if there is some connection, you need to do that before all that code, display an error and return instantly if connection is not available. However, the author tried to keep things simple, assuming there is always Internet connection.
Hope it makes you understand it.
This is the some code you can use for checking if there is connection:
// show some activity indicator
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Do something...
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
NSURL *url = [NSURL URLWithString:#"http://www.apple.com/"];
NSString *s = [NSString stringWithContentsOfURL:url
encoding:NSUTF8StringEncoding
error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
// hide the activity indicator
self.connected = (s != nil);
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
if (self.isConnected)
{
NSLog(#"self.connected == YES");
}
else
{
NSLog(#"self.connected == NO");
NSString *alertMessage = #"In order to load images, you need an active Internet connection. Please try again later!";
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sorry!"
message:alertMessage
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
});
});
You obviously need to add a property to you class. You can insert this code:
#interface LDPhotosViewController ()
#property (nonatomic, copy, getter = isConnected) NSString *connected;
#end
at the top of LDPhotosViewController.m file, before the #implementation line.

EXC_BAD_ACCESS code=1, address)xd84253e0

I keep getting this break point appear on my project which then causes the app to stop running.
It doesn't break in the thread results it seems to break on this line:
[urlString appendString: [URLQueryGenerator createSearchURL]];
The method that that line of code is in is as follows:
- (void)loadData {
[_appDelegate reloadFavourites];
if (_appDelegate.properties.count < 1) {
//Reset Results page number to one. Because the results are starting afresh.
[self setCurrentSearchPage:1];
[self.navigationItem setTitle:NSLocalizedString(#"Search Results", nil) ];
//Create URL String
NSMutableString *urlString = [[NSMutableString alloc] initWithString: #""];
[urlString appendString: [URLQueryGenerator createSearchURL]];
NSLog(#"%#", urlString);
[xmlParser parseXMLPage:urlString withDelegate:self];
[v_loadingView setHidden:NO];
//Do not release Parser here, released in dealloc()
//[xmlParser release];
}
else
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
[self loadCells];
else
[table reloadData];
}
}
I have put a break point on the search button that i have which then takes me to the results page to see if i could debug whats happening but its not giving a clear indication as to why i keep getting this error.
I have tried enabling zombie Object on the project but this still doesn't give me any indication.
Its really bugging me because i don't know how i can debug it well enough to find out why its doing this!
Can any one help please?

QuickBlox :How to share image/video in peer to peer chat module?

I am trying to share image/video in chat module. I've referred Sample code for this but couldn't find any help.
Alos I've referred http://quickblox.com/modules/chat/ it says Add live chat functions to your app by plugging in our full featured chat module. Fast, Firewall friendly, Robust & Secure. Does it means I have to purchase full featured chat module ?
Please suggest me the right way.
Thanks
Yes, QuickBlox Chat allows to share files, video/audio between 2 users.
Right now iOS SDK doesn't provide methods for send file, live chat. This feature is under Beta testing right now. We are developing easy interface for end users, and we need more time for this. I hope, we will finish it at the end of December.
However, we allow developers develop this feature themself.
What you need for this?
Just create simple TCP/UDP socket between 2 users and send files, audio/video stream through it
For 1 you need to know each other ip address & port - there is STUN protocol that allow to know own address(IP & port) - here is my iOS implementation of STUN protocol https://github.com/soulfly/STUN-iOS
If you already know your address (IP & port) - just send it to your opponent through simple Chat messages - then do 1 item.
Thats all what you need
UPD:
QuickBlox has released VideoChat and Unlimited API Calls for Developers http://quickblox.com/blog/2013/02/quickblox-updates-videochat-and-unlimited-api-calls-for-developers
So, if you want to play with the code and integrate it with your apps, check the Simple Code Sample for iOS http://quickblox.com/developers/SimpleSample-videochat-ios
You have a uploadMethod like this,
-(IBAction)uploadFile:(id)sender
{
self.imagePicker = [[UIImagePickerController alloc] init];
self.imagePicker.allowsEditing = NO;
self.imagePicker.delegate = self;
self.imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:self.imagePicker animated:YES completion:nil];
}
and in the QBChatDelegate, you have this method
- (void)completedWithResult:(Result*)result{
// Upload file result
if(result.success && [result isKindOfClass:[QBCFileUploadTaskResult class]])
{
QBCFileUploadTaskResult *res = (QBCFileUploadTaskResult *)result;
NSUInteger uploadedFileID = res.uploadedBlob.ID;
QBChatMessage *message = [[QBChatMessage alloc] init];
message.recipientID = self.opponent.ID;
NSMutableDictionary *msgDict = [[NSMutableDictionary alloc]init];
[msgDict setValue:[NSNumber numberWithInt:uploadedFileID] forKey:#"fileID"];
message.customParameters = msgDict;
[[QBChat instance] sendMessage:message];
}
else
{
NSLog(#"errors=%#", result.errors);
}
}
Here you are getting the uploaded file id, and you are sending this as a message..
In your chatDidReceiveNotification
- (void)chatDidReceiveMessageNotification:(NSNotification *)notification{
QBChatMessage *message = notification.userInfo[kMessage];
if(message.customParameters != nil)
{
NSUInteger fileID = [message.customParameters[#"fileID"] integerValue];
// download file by ID
[QBContent TDownloadFileWithBlobID:fileID delegate:self];
}
}
This method again calls completedWithResult method, add this code there...
if(result.success && [result isKindOfClass:[QBCFileDownloadTaskResult class]]){
QBCFileDownloadTaskResult *res = (QBCFileDownloadTaskResult *)result;
if ([res file]) {
UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageWithData:[res file]]];
[self.messages addObject:imageView];
[self.messagesTableView reloadData];
}
}else{
NSLog(#"errors=%#", result.errors);
}
If you want to display the image in your tableView, change your cellForRow like this..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([[self.messages objectAtIndex:indexPath.row]isKindOfClass:[QBChatMessage class]])
{
static NSString *ChatMessageCellIdentifier = #"ChatMessageCellIdentifier";
ChatMessageTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ChatMessageCellIdentifier];
if(cell == nil){
cell = [[ChatMessageTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ChatMessageCellIdentifier];
}
QBChatMessage *message = (QBChatMessage *)self.messages[indexPath.row];
//
[cell configureCellWithMessage:message is1To1Chat:self.opponent != nil];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
else if ([[self.messages objectAtIndex:indexPath.row]isKindOfClass:[UIImageView class]])
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellIdentifier"];
if (nil == cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:#"CellIdentifier"];
}
UIImageView *receivedImage = [self.messages objectAtIndex:indexPath.row];
[cell.contentView addSubview:receivedImage];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
}
I have tried this and this piece of code works.
Cheers.
If your requirement is only for 1-1 chat, then please check this link
http://quickblox.com/developers/SimpleSample-chat_users-ios#Send_files
This will work for 1-1 chat.
But, in case of room I am unable to find any solution as of now. I am trying to figure out. If anybody knows a way, please post here.

ShareKit email form not always displaying

I'm using ShareKit to share objects to Twitter, Facebook, and Email. Twitter and Facebook works fine, but email doesn't. And I don't really know why.
It seems like it works quite randomly.
I set it up like this:
[self.customView.shareButton addTarget:self action:#selector(sharePost:) forControlEvents:UIControlEventTouchUpInside];
- (void)sharePost:(UIButton *)sender
{
NSURL *url = [NSURL URLWithString:self.currentPost.link];
// Add image.
NSString *imageUrlString = [NSString stringWithFormat:[link]];
NSURL *imageUrl = [NSURL URLWithString:imageUrlString];
UIImageView *postImage = [[UIImageView alloc] init];
[postImage setImageWithURL:imageUrl];
SHKItem *item = [SHKItem image:postImage.image title:[NSString stringWithFormat:#"%#", self.currentPost.title]];
[item setURL:url];
[item setMailBody:[NSString stringWithFormat:#"%# %#", self.currentPost.title, self.currentPost.link]];
// Get the ShareKit action sheet
// This works
SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item];
// ShareKit detects top view controller (the one intended to present ShareKit UI) automatically,
// but sometimes it may not find one. To be safe, set it explicitly.
[SHK setRootViewController:self];
// Display the action sheet.
[actionSheet showInView:self.view];
}
Any ideas or what I'm missing or doing wrong?
Try to change the RootViewController and view you are using:
[SHK setRootViewController:self.view.window.rootViewController];
[actionSheet showInView:self.view.window.rootViewController.view];
Most likely your view controller hierarchy is somewhat messed up.