I want to put an alert view on a 15 minute timer with a YES or NO button. This works fine if the user stays on that view. However the UIAlertView uses a local variable for its title and in the delegate method. When the user changes views the program crashes. Can I make a UIAlertView wait for 15 minutes then implement the delegate method? I tried to put the delegate method in other views, but don't know how to pass the variable with the alert. I've done a little research and think maybe with a Notification or background thread (but background threads I don't think can do UI stuff and an alert is UI)
- (IBAction)sendInAppMsg:(UIButton *)sender
{
....
//****This is the message that calls the UIAlertView on a timer
[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(pause) userInfo:nil repeats:NO];
}
-(void) pause
{
UIAlertView *responseAlert = [[UIAlertView alloc] initWithTitle:#"Success?" message:[NSString stringWithFormat:#"Did you reach %# %#", self.currentDoc.firstName, self.currentDoc.lastName ] delegate:self cancelButtonTitle:nil otherButtonTitles:#"Yes", #"No", nil];
[responseAlert show];
}
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
//Update Parse Cloud with users response
PFObject *contactAttempt = [PFObject objectWithClassName:#"ContactAttempt"];
contactAttempt [#"inApp"] = #"push";
contactAttempt [#"from"] = [[PFUser currentUser] username];
contactAttempt [#"to"] = [NSString stringWithFormat:#"%# %#", self.currentDoc.firstName, self.currentDoc.lastName ];
if (buttonIndex == 0) {
contactAttempt [#"response5"] = #YES;
[contactAttempt saveInBackground];
}
if (buttonIndex == 1)
{
contactAttempt [#"response5"] = #NO;
[contactAttempt saveInBackground];
}
}
//works fine and updates cloud with user response unless user changes views :(
Related
I am new in objective C.Execute this Program ON Clicking on button"Click here to sell your Gold now"
It will lunch you to dashboard.In dashboard select Transaction History.I have fetchNewHothistory function in TransactionHistoryViewController.m file responsible for fetching data from url and displaying it onto the viewcontroller file
-(void)fetchNewHothistory
{
NSTimer *t = [NSTimer scheduledTimerWithTimeInterval:1.0
target: self
selector:#selector(mytimerChecking:)
userInfo: nil repeats:NO];
NSMutableDictionary *paramDict=[NSMutableDictionary dictionary];
[paramDict setObject:#"ios" forKey:#"request"];
[paramDict setObject:[NSString stringWithFormat:#"%#",currentUser.user_id] forKey:#"user_id"];
[paramDict setObject:[NSString stringWithFormat:#"%#",self.currentLimitNew] forKey:#"limit_start"];
[GeneralWebservices webserviceMainSplashCall:paramDict webserviceName:Webservice_TransactionHistory OnCompletion:^(id returnDict, NSError *error) {
if ([returnDict[#"success"] intValue] ==1)
{
// UIAlertView* alert = [[UIAlertView alloc] init];
// [alert setTitle:#"RECORD FOUND"];
// // [alert setMessage:returnDict[#"message"]];
// [alert addButtonWithTitle:#"OK"];
// [alert show];
[history addObjectsFromArray:returnDict[#"data"]];
self.currentLimitNew=[NSString stringWithFormat:#"%#",returnDict[#"limit_start"]] ;
[historyTableView reloadData];
}
else
{
UIAlertView* alert = [[UIAlertView alloc] init];
[alert setTitle:#"RECORD FOUND"];
//[alert setMessage:returnDict[#"message"]];
[alert addButtonWithTitle:#"OK"];
[alert show];
}
[MBProgressHUD hideAllHUDsForView:self.view animated:YES];
[historyTableView.pullToRefreshView stopAnimating];
[historyTableView.infiniteScrollingView stopAnimating];
}];
}
Issue -1
Record found but nothing displayed on Viewcontroller on selecting the Transaction History.The How to display record onto viewcontroller?
Issue -2
In on selecting Profile the ProfileViewController.m is executed .On updating the user profile .It does not updates .It remain buffering .How to perform profile update .
you can download the project from this link .https://drive.google.com/file/d/1daW4veZAI21b8TqKFHauSFTboHKJceaG/view?usp=sharing
Try this:
dispatch_async(dispatch_get_main_queue(), ^{
[historyTableView reloadData];
});
I have an iOS app with Facebook functionality and a Parse backend. In the social media app, there is an ActivityViewController that shows: likes, comments, followers. That code is connected to my js cloud code for push notifications through Parse.
While I have comment notifications working great if userA comments on usersB's post (userB is notified), I want to add notification for a "UserB replied to your comment" activity portion (where userA is notified that there's been a response from UserB while it's on their post). Probably explaining that terribly, but basically pretty similar to face book's notifications in the comments portion but right now notifications are only one sided. I have been to work it, but I seem to only get users notifying themselves that they replied to a post.
I'm having a little trouble wrapping my head around the best way to implement that. The constants, cloud code and caches should be set up correctly. Code Below.
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
// Comment Portion, works fine
NSString *trimmedComment = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (trimmedComment.length != 0 && [self.photo objectForKey:kPAPPhotoUserKey]) {
PFObject *comment = [PFObject objectWithClassName:kPAPActivityClassKey];
[comment setObject:trimmedComment forKey:kPAPActivityContentKey]; // Set comment text
[comment setObject:[self.photo objectForKey:kPAPPhotoUserKey] forKey:kPAPActivityToUserKey]; // Set toUser
[comment setObject:[PFUser currentUser] forKey:kPAPActivityFromUserKey]; // Set fromUser
[comment setObject:kPAPActivityTypeComment forKey:kPAPActivityTypeKey];
[comment setObject:self.photo forKey:kPAPActivityPhotoKey];
PFACL *ACL = [PFACL ACLWithUser:[PFUser currentUser]];
[ACL setPublicReadAccess:YES];
[ACL setWriteAccess:YES forUser:[self.photo objectForKey:kPAPPhotoUserKey]];
comment.ACL = ACL;
[[PAPCache sharedCache] incrementCommentCountForPhoto:self.photo];
// Show HUD view
[MBProgressHUD showHUDAddedTo:self.view.superview animated:YES];
// If more than 5 seconds pass since we post a comment, stop waiting for the server to respond
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:#selector(handleCommentTimeout:) userInfo:#{#"comment": comment} repeats:NO];
[comment saveEventually:^(BOOL succeeded, NSError *error) {
[timer invalidate];
if (error && error.code == kPFErrorObjectNotFound) {
[[PAPCache sharedCache] decrementCommentCountForPhoto:self.photo];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Could not post comment", nil) message:NSLocalizedString(#"This photo is no longer available", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
[self.navigationController popViewControllerAnimated:YES];
}
[[NSNotificationCenter defaultCenter] postNotificationName:PAPPhotoDetailsViewControllerUserCommentedOnPhotoNotification object:self.photo userInfo:#{#"comments": #(self.objects.count + 1)}];
[MBProgressHUD hideHUDForView:self.view.superview animated:YES];
[self loadObjects];
}];
}
//Reply portion is getting me stuck
NSString *trimmedReply = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (trimmedReply.length != 0 && [self.photo objectForKey:kPAPPhotoUserKey]) {
PFObject *reply = [PFObject objectWithClassName:kPAPActivityClassKey];
[reply setObject:trimmedReply forKey:kPAPActivityContentKey]; // Set reply text
[reply setObject:[self.photo objectForKey:kPAPPhotoUserKey] forKey:kPAPActivityFromUserKey]; //CHANGED TO FromUser
[reply setObject:[PFUser currentUser] forKey:kPAPActivityToUserKey]; // Changed ToUser
[reply setObject:kPAPActivityTypeReply forKey:kPAPActivityTypeKey];
[reply setObject:self.photo forKey:kPAPActivityPhotoKey];
PFACL *ACL = [PFACL ACLWithUser:[PFUser currentUser]];
[ACL setPublicReadAccess:YES];
[ACL setWriteAccess:YES forUser:[self.photo objectForKey:kPAPPhotoUserKey]];
reply.ACL = ACL;
[[PAPCache sharedCache] incrementReplyCountForPhoto:self.photo];
// Show HUD view
[MBProgressHUD showHUDAddedTo:self.view.superview animated:YES];
// If more than 5 seconds pass since we post a reply, stop waiting for the server to respond
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0f target:self selector:#selector(handleReplyTimeout:) userInfo:#{#"reply": reply} repeats:NO];
[reply saveEventually:^(BOOL succeeded, NSError *error) {
[timer invalidate];
if (error && error.code == kPFErrorObjectNotFound) {
[[PAPCache sharedCache] decrementReplyCountForPhoto:self.photo];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Could not post reply", nil) message:NSLocalizedString(#"This photo is no longer available", nil) delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alert show];
[self.navigationController popViewControllerAnimated:YES];
}
[[NSNotificationCenter defaultCenter] postNotificationName:PAPPhotoDetailsViewControllerUserRepliedOnPhotoNotification object:self.photo userInfo:#{#"replies": #(self.objects.count + 1)}];
[MBProgressHUD hideHUDForView:self.view.superview animated:YES];
[self loadObjects];
}];
}
///^^^
[textField setText:#""];
return [textField resignFirstResponder];
}
I have a problem with UIAlertView message, I need to change alert message with loop
First,
I declare this in implementation
NSString *alertMessage;
UIAlertView *theAlert;
and
- (IBAction)doSearching:(id)sender
{
theAlart = [[UIAlertView alloc] initWithTitle:nil message:#"Searching..."
delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
[theAlart show];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self
selector:#selector(searchAfterAlertShow) userInfo:nil repeats:NO];
}
- (void)searchAfterAlertShow
{
for (int i = 0; i < [dataArray count]; i++) {
alertMessage = [NSString stringWithFormat:#"Searching... (%d/%d)"
, i, [dataArray count]];
NSLog(#"%#", alertMessage);
// do something here
if (i == [dataArray count]) {
[theAlart dismissWithClickedButtonIndex:0 animated:YES];
}
}
}
and in Alert delegate
- (void)didPresentAlertView:(UIAlertView *)alertView
{
[theAlart setMessage: alertMessage];
}
The Log is writing:
Searching... (1/8)
Searching... (2/8)
...
Searching... (8/8)
but the alert message changed at the end of loop
If the operations are too fast, the dismiss animation will take longer than the loop itself.
Most UI animations are async, therefore they happen in the background and they don't wait. you can either delay the operation to compensate for the animation duration, or pass NO for animated parameter in dismissWithClickedButtonIndex:animated
I define a UIAlertView, its tag = 101, to determine save or not, show another UIAlertView called alertView2 when clicked save button, and then delete the subviews of rootView. But when I call clear Code [self clearAllSubviewsInRootView];here, it clear subViews before call alertView2. How do I fix it?
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (alertView.tag == 101)
{
if (buttonIndex == 0)
{
}
else
{
if (buttonIndex == 1)
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"input fileName" message:nil delegate:self cancelButtonTitle:#"cancel" otherButtonTitles:#"OK", nil];
alertView.tag = 102;
alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
[alertView show];
}
[self clearAllSubviewsInRootView];
}
}
if (alertView.tag == 102)
{
if (buttonIndex == 0)
{
}
else
{
NSArray *viewArray = [self.canvasView subviews];
NSUserDefaults *UD = [NSUserDefaults standardUserDefaults];
NSString *scaleStr = [UD objectForKey:#"scale"];
NSArray *dataArray = [NSArray arrayWithObjects:scaleStr, _labelArrivalTime.text, _textAccidentLocation.text,
_textDeclare.text, _textWeather.text, _textRoadSurface.text, [NSNumber numberWithFloat:canvasSize], nil];
NSMutableArray *array = [NSMutableArray arrayWithObjects:viewArray, dataArray, nil];
NSData * encodedata=[NSKeyedArchiver archivedDataWithRootObject:array];
NSString *fileName = [alertView textFieldAtIndex:0].text;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *floerName = #"file";
NSString *saveDirectory = [[paths objectAtIndex:0] stringByAppendingPathComponent:floerName];
NSString *filePath = [saveDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.rta", fileName]];
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:filePath])
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"file existed" message:nil delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
alertView.tag = 103;
[alertView show];
}
else
{
[encodedata writeToFile:filePath atomically:YES];
[self saveImage:_prospector.image :filePath :#"勘查员"];
[self saveImage:_draftman.image :filePath :#"绘图员"];
[self saveImage:_person.image :filePath :#"当事人"];
}
}
}
}
UIAlertViews are modal views, but that does not mean they are synchronous.
In fact, UIAlertViews are asynchronous modal views.
In plain english, that means that they will be presented on screen, but some other code may be executed simultaneously (= asynchronous). So, code execution does not stop after calling [myAlert show]. The user however, is not able to select something else, he or she must deal with this one and only element on screen (= modal).
Having said that: I do not know the exact implementation of UIAlertViews, but it would not surprise me if the current runloop is being run to the end until the alert is actually presented on screen. That means, all code after [alertView show] will be executed to the end, and only then the alert will show (with the next runLoop).
So, you are asking "why it clears subviews before showing the second alert", but this is exactly what you tell it to do:
if (buttonIndex == 1)
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"input fileName" message:nil delegate:self cancelButtonTitle:#"cancel" otherButtonTitles:#"OK", nil];
alertView.tag = 102;
alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
[alertView show]; // <-- you show the alert
}
[self clearAllSubviewsInRootView]; // <—- and clear all views
You are creating and showing the second view and then immediately call [self clearAllSubviewsInRootView] after [alertView show].
If you want to clearAllSubviews only after the user has selected something in the second alert view, you must move this call [self clearAllSubviewsInRootView]to a later point in your if (alertView.tag == 102) routine
The main problem here js you override name of the alertView inside method:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
You have here property named alertView. Later you declare:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"input fileName" message:nil delegate:self cancelButtonTitle:#"cancel" otherButtonTitles:#"OK", nil];
This is a bit confusing and i'm not sure what are you trying to achieve here.
But GCD seems to fitting your problem so Apple provide here a useful snippet (you can call it by start writing dispatch_after):
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//put code here, whatever you want to fire later (after two seconds in this case)
});
In your case you probably want (i'm not sure) to keep second alert view after code is completed. In this case you should
This works for me,.. And it so simple you can use this for an infinite alertview.
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if ([alertView.title isEqualToString:#"First Alertview Title"]) {
if (buttonIndex == [alertView cancelButtonIndex]) {
// do your stuff in cancel button --->First Alert
} else if (buttonIndex == 1) {
// do your stuff in other button ----> First Alert
}
} else if ([alertView.title isEqualToString:#"Second Alertview Title"]) {
if (buttonIndex == [alertView cancelButtonIndex]) {
// do your stuff in cancel button ----> Second Alert
} else if (buttonIndex == 1) {
// do your stuff in other button -----> Second Alert
}
}
}
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.