I am using multipeer connectivity and this is one of the methods:
-(void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress
{
NSLog(#"RECEIVING... %# from peer: %#", progress, peerID);
UIProgressView *progressBar = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleBar];
progressBar.frame = CGRectMake(0, 200, 100, 20);
progressBar.progress = 0.5;
UIButton* btn = [BluetoothDeviceDictionary objectForKey:peerID];
[self.view addSubview:progressBar];
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:#"Alert View Title" message:#"Alert View Text" delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alertView show];
}
For some VERY STRANGE reason, when this method is called, and I know it is called because of the response from the NSLog, the rest of the code is not executed. The alert appears 20 seconds (more or less) after the NSLog has appeared, and the progress view never appears. I can't get why. This happens for most of the methods in multipeer connectivity framework. How is this possible?
EDIT: actually the progress view appears, but much much after the method is called
It's possible that the session delegate's method is being invoked on a background thread. UIKit calls should only be made on the main thread, so you may need to move your code that interacts with UIKit to another method like this:
- (void) updateUI {
UIProgressView *progressBar = [[UIProgressView alloc];
initWithProgressViewStyle:UIProgressViewStyleBar];
progressBar.frame = CGRectMake(0, 200, 100, 20);
progressBar.progress = 0.5;
UIButton* btn = [BluetoothDeviceDictionary objectForKey:peerID];
[self.view addSubview:progressBar];
UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:#"Alert View Title" message:#"Alert View Text" delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alertView show];
}
and then call it using:
-(void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress
{
NSLog(#"RECEIVING... %# from peer: %#", progress, peerID);
[self performSelectorOnMainThread:#selector(updateUI) withObject:nil waitUntilDone:YES];
}
Related
I have an UIAlertView with the UIActivityIndicatorView.
UIAlertView *alertView_Spinning =
[[UIAlertView alloc] initWithTitle:#"Please wait"
message:#"Connecting to server"
delegate:nil
cancelButtonTitle:nil
otherButtonTitles: nil];
alertView_Spinning.tag=0;
UIActivityIndicatorView *indicator =
[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[indicator startAnimating];
[alertView_Spinning setValue:indicator forKey:#"accessoryView"];
[alertView_Spinning show];
How can I dismiss this alert from the below method:Can I use alert tag for dismissing?. I am not including any buttons in my alert view.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
//dismiss alert view here
}
You should assign it to an ivar or property of your current class instead of as a local variable, then call dismissWithClickedButtonIndex:animated: in the connectionDidFinishLoading: handler.
I have one alert view and when I click on yes button it is supposed to produce another alert view and a toast message,but it is not happening. I couldn't figure it out. Here is my code:
-(void)myMethod {
UIAlertView *saveAlert = [[UIAlertView alloc] initWithTitle:#"First Message"
message:#"My First message"
delegate:nil
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
saveAlert.tag=0;
[saveAlert performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:NO];
}
This is the method I am using to provide the functionality for different alert views.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(alertView.tag==0) {
if (buttonIndex == 0)
{
//Code for Cancel button
}
if (buttonIndex == 1)
{
//code for yes button
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
hud.mode = MBProgressHUDModeText;
hud.labelText = #"Successfully displayed First Message";
hud.margin = 10.f;
hud.yOffset = 150.f;
hud.removeFromSuperViewOnHide = YES;
[hud hide:YES afterDelay:3];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Second Message"
message:#"My second message"
delegate:nil
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes",nil];
alert.tag=1;
[alert performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
}
}
if (alertView.tag==1) {
if (buttonIndex == 0)
{
//Code for Cancel button
}
if (buttonIndex == 1)
{
//Code for yes Button
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
hud.mode = MBProgressHUDModeText;
hud.labelText = #"Succesfully displayed Second Message";
hud.margin = 10.f;
hud.yOffset = 150.f;
hud.removeFromSuperViewOnHide = YES;
[hud hide:YES afterDelay:3];
}
}
}
Can anyone help in finding the issue. Why I cannot get my second alert after clicking yes button in first alert?
You have not set the delegate for your UIAlertView and also make sure your delegate conforms to UIAlertViewDelegate protocol. Find the code snippet below.
You controller conforms to UIAlertViewDelegate protocol:
#interface YourViewController : UIViewController <UIAlertViewDelegate>
Create UIAlertView and set the deleagte:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"First Message"
message:#"Show second message"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
[alertView show];
Implement UIAlertViewDelegate delegate method:
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if( 0 == buttonIndex ){ //cancel button
[alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
} else if ( 1 == buttonIndex ){
[alertView dismissWithClickedButtonIndex:buttonIndex animated:YES];
UIAlertView * secondAlertView = [[UIAlertView alloc] initWithTitle:#"Second Message"
message:#"Displaying second message"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[secondAlertView show];
}
}
You are specifying nil as the delegate for your alert views. You need to specify an object so the alertView:clickedButtonAtIndex: method can be called!
If you'd like to handle this more clear, you could use a block-based AlertView.
Create new file->Subclass of->UIAlertView
SuperAlertView.h
#import <UIKit/UIKit.h>
#class MySuperAlertView;
typedef void (^MySuperAlertViewBlock) (MySuperAlertView *alertView);
#interface MySuperAlertView : UIAlertView
- (instancetype) initWithTitle:(NSString *)title message:(NSString *)message;
- (void) addButtonWithTitle:(NSString *)buttonTitle block:(MySuperAlertViewBlock) block;
#end
SuperAlertView.m
#import "MySuperAlertView.h"
#interface MySuperAlertView()<UIAlertViewDelegate>
#property NSMutableArray *blocks;
#end
#implementation MySuperAlertView
- (instancetype)initWithTitle:(NSString *)title message:(NSString *)message
{
if (self = [super initWithTitle:title message:message delegate:self cancelButtonTitle:nil otherButtonTitles:nil])
{
self.blocks = [NSMutableArray array];
}
return self;
}
- (void)addButtonWithTitle:(NSString *)buttonTitle block:(MySuperAlertViewBlock)block
{
[self addButtonWithTitle:buttonTitle];
[self.blocks addObject:block ? [block copy] : [NSNull null]];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
MySuperAlertViewBlock block = self.blocks[buttonIndex];
if ((id) block != [NSNull null]){
block(self);
}
}
#end
Usage:
MySuperAlertView *alertView = [[MySuperAlertView alloc] initWithTitle:#"Info" message:NSLocalizedString(#"EMAIL_SENT_SUCCESSFULL", nil)];
[alertView addButtonWithTitle:#"Ok" block:^(MySupertAlertView *alertView) {
// handle result from ok button here
}];
[alertView addButtonWithTitle:#"cancel" block:NULL];
dispatch_async(dispatch_get_main_queue(), ^{
[alertView show];
});
An async request has been sent to the server and here is my connection delegate.
in RKYLoginDelegate.m file, i made an alert to tell user that the member is verifying when receiving data.
didReceivedData
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_receivedData appendData:data];
loginAlertView = [[UIAlertView alloc] initWithTitle:#"message"
message:#"verifying member..."
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
[loginAlertView performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
NSLog(#"Received data: %#", [[NSString alloc] initWithData:_receivedData encoding:NSUTF8StringEncoding]);
}
and in finish loading data, if nothing return, then shows the error message.
didFinishLoading
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
in the code, it will verify return state and parse value, if not respond then alert a dialog to notify user error message
if ([jsonDataDictionary count] > 0) {
// add member into data
RKYMemberManager *rkyMemberManager = [RKYMemberManager new];
[rkyMemberManager addMember:jsonDataDictionary];
// navigate to main
UIStoryboard *rkyMainStoryboard = [UIStoryboard storyboardWithName:#"RKYMainStoryboard" bundle:nil];
RKYMainViewController *rkyMainViewController =
[rkyMainStoryboard instantiateViewControllerWithIdentifier:#"RKYMain"];
[[[UIApplication sharedApplication] delegate].window.rootViewController.navigationController presentViewController:rkyMainViewController animated:YES completion:nil];
}
else {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:#"message"
message:#"Cannot login!"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
[alertView show];
NSLog(#"cannot login");
}
Those alert dialogs did show its message, but will cause an error:
Thread 1:EXC_BAD_ACCESS(code=2, address=0xc)
as title, am I doing correctly?
if yes, how to solve the problem that caused?
I tried to add some operations after call
- (void)parserDidStartDocument:(NSXMLParser *)parser {
//NSLog(#"found file and started parsing");
alertView = [[UIAlertView alloc] initWithTitle:#"Caricamento..."
message:#"\n"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(139.5, 75.5); // .5 so it doesn't blur
[alertView addSubview:spinner];
[spinner startAnimating];
[alertView show];
}
But it freeze the app for a while, and then, when finished the XML parse, loads the AlertView, ecc. Same thing with the UIRefreshControl. I slide down the tableView, and the app freeze while parsing, I cant see the spinner rotating.
Any idea?
Edit:
here I call the first time the parser:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSString * path = #"thexmlpath.xml";
if(!caricato)
[NSThread detachNewThreadSelector:#selector(parseXMLFileAtURL:) toTarget:self withObject:path];
//[self parseXMLFileAtURL:path];
caricato = YES;}
Here I call when I use the RefreshControl:
- (void)refreshControlRequest{
NSLog(#"refreshing...");
NSString * path = #"thexmlpath.xml";
[self performSelector:#selector(parseXMLFileAtURL:) withObject:path];}
hope this will help you
- (void)parserDidStartDocument:(NSXMLParser *)parser {
//NSLog(#"found file and started parsing");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
alertView = [[UIAlertView alloc] initWithTitle:#"Caricamento..."
message:#"\n"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:nil];
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.center = CGPointMake(139.5, 75.5); // .5 so it doesn't blur
[alertView addSubview:spinner];
[spinner startAnimating];
[alertView show];
});
dispatch_release(queue);
}
I want to know if it is possible for an AlertView to time out if it has been visible on the screen for a certain period of time without receiving any acknowledgement from the user, and if so, how? Is there a way for the AlertView object be linked with an NSTimer object?
My basic AlertView code is the following:
- (IBAction)showMessage:(id)sender {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Hello World!"
message:#"This is your first UIAlertview message."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[message show];
}
This is how I implemented in one of my apps
Inside the #interface declare your objects so you can keep track of them and add the if required
#property (nonatomic, strong) UIAlertView *myAlert;
#property (nonatomic, weak) NSTimer *myTimer;
In your code where you need to launch the alert add the following
self.myAlert = [[UIAlertView alloc]initWithTitle:#"TEST" message:#"TEST" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
self.myTimer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:#selector(cancelAlert) userInfo:nil repeats:NO];
[self.myAlert show];
Somewhere in your code add next function to dismiss the alert and invalidate the NSTimer
- (void)cancelAlert {
[self.myAlert dismissWithClickedButtonIndex:-1 animated:YES];
}
Also remember to invalidate the timer if a button is touched.
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex {
[self.myTimer invalidate];
// Process pressed button
}
It may need some tweaks for your requirements.
Yes. Use dismissWithClickedButtonIndex:animated:
For example with a dispatch_after block, like this:
int64_t delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[message dismissWithClickedButtonIndex:message.cancelButtonIndex animated:YES];
});
If you want to use a NSTimer just save the UIAlertView in an instance variable so you can access it from within the timer method.
You could create a category for UIAlertView and add an observer which listens out and if it is triggered, removes itself:
#implementation UIAlertView (Cancellable)
+ (instancetype)cancellableAlertViewWithTitle:(NSString *)title
message:(NSString *)message
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ...
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:delegate
cancelButtonTitle:cancelButtonTitle
otherButtonTitles:nil];
if (otherButtonTitles != nil)
{
va_list args;
va_start(args, otherButtonTitles);
for (NSString *buttonTitle = otherButtonTitles; buttonTitle != nil; buttonTitle = va_arg(args, NSString*))
{
[alertView addButtonWithTitle:buttonTitle];
}
va_end(args);
}
[[NSNotificationCenter defaultCenter] addObserver:alertView selector:#selector(removeAlertView:) name:#"AlertsShouldBeCancelledNotification" object:nil];
return alertView;
}
- (void)removeAlertView:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self dismissWithClickedButtonIndex:-1 animated:YES];
}
#end
Then you could create an NSTimer in your main class and have it trigger the notification when the selector is called.
Use an NSTimer to call dismissWithClickedButtonIndex:animated: and invalidate it if the user clicks in time. Using dispatch_after risks sending the message to a released instance if the user has dismissed it already.
Take a look at this answer: dismissing a UIAlertView programmatically . Using performSelector:withObject:afterDelay: is much more elegant than building and tearing down a timer, in my opinion.