There is an issue with an UIAlertView when i add to this a lot of buttons. Then the alertView seems to be destroyed. This happens only to prior version of iOS 7. On iOS 7 and posterior versions it seems ok.Here is a screenshot of my problem.Can i fix it?
- (void) sortTotalMnhmeia{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Ταξινόμηση" message:#"Επιλέξτε είδος ταξινόμησης" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Αξιοθέατα",#"Δραστηριότητες",#"Διαμονή",#"Χωριά",#"Προϊόντα",#"Όλες οι κατηγορίες",nil];
[alert show];
}
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0)
{
NSLog(#"Cancel Tapped.");
}
else if (buttonIndex == 1)
{
[self.mapView removeAnnotations:self.annotations];
[self.annotations removeAllObjects];
self.annotations=[[NSMutableArray alloc] init];
NSLog(#"yo %d",self.annotations.count);
for(int i=0; i<self.allGroups.count; i++){
Group *assistantGroup=assistantGroup=[self.allGroups objectAtIndex:i];
if ([assistantGroup.secondLevel intValue]==1) {
if ([assistantGroup.thirdLevel intValue]==1) {
self.chooseMarker=#"Museum";
}
else if ([assistantGroup.thirdLevel intValue]==2) {
self.chooseMarker=#"Art";
}
else if ([assistantGroup.thirdLevel intValue]==3) {
self.chooseMarker=#"Religious";
}
else if ([assistantGroup.thirdLevel intValue]==4) {
self.chooseMarker=#"Monument";
}
else if ([assistantGroup.thirdLevel intValue]==5) {
self.chooseMarker=#"Natural";
}
else if ([assistantGroup.thirdLevel intValue]==6) {
self.chooseMarker=#"Beach";
}
NSLog(#"************ %# %# %#",assistantGroup.title,assistantGroup.latitude,assistantGroup.longitude);
Annotation *ann = [[Annotation alloc] initWithLong:[assistantGroup.longitude doubleValue] Lat:[assistantGroup.latitude doubleValue] iconNumber:0];
ann.title = assistantGroup.title;
ann.subtitle=#"";
ann.type=self.chooseMarker;
[self.annotations addObject:ann];
}
//ann.type=assistantGroup.kind;
}
[self.mapView addAnnotations:self.annotations];
}
.....
}
You should consider using a modal view controller instead since using lots of buttons in an AlertView can be confusing. I don't see the reason adding lots of buttons to a single alert view. A modal VC has all the flexibility you are looking for. Otherwise an action sheet would be preferable too.
But to answer the question: Add a "More" button last that spawns a second AlertView with the buttons that don't fit the first alert view. Alert VCs don't rescale the way they do on iOS versions above 7.0.
Related
I've just implemented a commenting feature in my app. Ideally when someone leaves a comment, I'd like all notified people be able to swipe the push notification and open the app on that post.
I assume you want to open the concerned page directly. There are many ways to go about this, and it depends on how your app is laid out.
If you want to open an inner page upon app launch, you can programmatically trigger the segues that the user would otherwise need to make manually. (this ensures the back/home buttons work as opposed to loading the desired page directly).
Here's an excerpt from one of my own code, your use case may not be the same, but this is all i can do unless you give us more details.
- (BOOL) navigateToRespectiveSectionforPushNot:(NSDictionary*)pushNot
{
id rootVC = self.window.rootViewController;
NSLog(#"ROOT CLASS : %#", [rootVC class]);
if ([rootVC isKindOfClass:[SWRevealViewController class]])
{
NSLog(#"Root Class looking good... mission Navigate!!");
SWRevealViewController *homeVC = (SWRevealViewController*) rootVC;
NSString *category = [[pushNot objectForKey:pushPayloadKeyaps] objectForKey:pushPayloadKeyCategory];
NSString *subCat = [[pushNot objectForKey:pushPayloadKeyaps] objectForKey:pushPayloadKeySubCategory];
NSLog(#"category : %# , subcat : %#",category,subCat);
//The code for the page to which i'm supposed to navigate to is contained in the push notification payload
if ([category isEqualToString:pushCategoryItemChat])
{
[homeVC.rearViewController performSegueWithIdentifier:#"chatPush" sender:nil];
UINavigationController *nc = (UINavigationController*)homeVC.frontViewController;
NSLog(#"FrontView Class : %#",[nc.viewControllers[0] class]);
UITableViewController *tvc = (UITableViewController*)nc.viewControllers[0];
NSDictionary *send = #{chatPushTargetUserId:subCat,chatPushTargetUserName:#"",chatPushTargetUserImage:#""};
[tvc performSegueWithIdentifier:#"seguePushDemoVC" sender:send];
return YES;
}
//communityPush historyPush
else if ([category isEqualToString:pushCategoryItemCommunity])
{
if ([subCat isEqualToString:pushSubCatItemNewRequest])
{
[homeVC.rearViewController performSegueWithIdentifier:#"communityPush" sender:nil];
return YES;
}
else if ([subCat isEqualToString:pushSubCatItemAccepted])
{
[homeVC.rearViewController performSegueWithIdentifier:#"communityPush" sender:nil];
return YES;
}
}
else if ([category isEqualToString:pushCategoryItemHistory])
{
[homeVC.rearViewController performSegueWithIdentifier:#"historyPush" sender:nil];
return YES;
}
}
else
{
UIAlertView *whoa = [[UIAlertView alloc] initWithTitle:#"WHOA!!" message:#" That wasn't supposed to happen. You are not even logged in. Call 911..." delegate:nil cancelButtonTitle:#"mmKay.." otherButtonTitles:nil, nil];
[whoa show];
}
return NO;
}
I hope the code is self explanatory. cheers
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I have an if statement that is working fine, but I need to add a 2nd if statement inside of it and I can't seem to figure out how to get it right.
Here is my code:
-(IBAction)xButton {
if([_hasUserTakenAPhoto isEqual: #"YES"]) {
_xButtonAfterPhotoTaken = [[UIActionSheet alloc] initWithTitle:#"Delete" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:nil];
[_xButtonAfterPhotoTaken showInView:self.view];
NSString *title = [_xButtonAfterPhotoTaken buttonTitleAtIndex:1];
if(title isEqualToString:#"Delete") {
[self performSegueWithIdentifier:#"backToHomeFromMediaCaptureVC" sender:self];
}
} else {
[self performSegueWithIdentifier:#"backToHomeFromMediaCaptureVC" sender:self];
}
}
I get errors when I add in the 2nd if statement of:
if(title isEqualToString:#"Delete") {
[self performSegueWithIdentifier:#"backToHomeFromMediaCaptureVC" sender:self];
}
I have tried making the 2nd if statement an "else if" but then it will not let me access the NSString object called "title". Is there an easier way to do this, or should I just make title a global variable?
UIActionSheets are not used that way:
- (IBAction)xButton:(UIButton*)sender
{
if ([_hasUserTakenAPhoto isEqual:#"YES"])
{
_xButtonAfterPhotoTaken = [[UIActionSheet alloc] initWithTitle:#"Delete Photo?" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:#"Delete" otherButtonTitles:nil];
[_xButtonAfterPhotoTaken showInView:self.view];
}
else
{
[self performSegueWithIdentifier:#"backToHomeFromMediaCaptureVC" sender:self];
}
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
// Check if it's the correct action sheet and the delete button (the only one) has been selected.
if (actionSheet == _xButtonAfterPhotoTaken && buttonIndex == 0)
{
[self performSegueWithIdentifier:#"backToHomeFromMediaCaptureVC" sender:self];
}
}
- (void)actionSheetCancel:(UIActionSheet *)actionSheet
{
NSLog(#"Canceled");
}
You gotta understand that interface elements are not "instant", there's plenty of asynchrony going on. When presenting an UIActionSheet for instance, the thread doesn't wait for the user to answer yes or no, it keeps running.
That's why there's delegates, and blocks, you present the UIActionSheet, and with the delegate you say "I'll take care of it when the user actually clicks it".
You'd be wondering, why not just wait for it to select it? Main thread takes care of updating the interface, animations, and retrieving user input (touches, keyboard taps, etc) and even running NSTimers that are subscript to the main NSRunLoop. Stopping main thread would lock the interface.
Try
- (IBAction)xButton
{
NSString *title;
if ([_hasUserTakenAPhoto isEqual:#"YES"])
{
_xButtonAfterPhotoTaken = [[UIActionSheet alloc] initWithTitle:#"Delete" delegate:self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:nil];
[_xButtonAfterPhotoTaken showInView:self.view];
title = [_xButtonAfterPhotoTaken buttonTitleAtIndex:1];
if ([title isEqualToString:#"Delete"])
{
[self performSegueWithIdentifier:#"backToHomeFromMediaCaptureVC" sender:self];
}
}
else
{
[self performSegueWithIdentifier:#"backToHomeFromMediaCaptureVC" sender:self];
}
}
I am new to IOS. I am making a login view controller in IOS with one button which is sign in. I have two possible view-controllers that might be shown when the user click on the sign-in button. I am using Storyboard but I can only assign one segue to one button. I don't know how to perform the condition since I seem not to have 100% control over the segue.
Here is my code:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *stringreponse=[[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
// NSLog(#"Split response %#", [splitresponse objectAtIndex:0]);
if([stringreponse isEqualToString:#"0"])
{
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"Wrong username or password" message:#"Wrong username or password" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
else
{
NSArray *splitresponse=[stringreponse componentsSeparatedByString:#"#"];
if([[splitresponse objectAtIndex:0] isEqualToString:#"Parent"])
{
if([[splitresponse objectAtIndex:2] isEqualToString:#"yes"])
{
//seguechoice=#"showParentRegistration";
//[self performSegueWithIdentifier:#"showParentRegistration" sender:self ];
}else{
//seguechoice=#"showSohoDashboard";
}
}
}
}
you can assign one segue to one UI control but you can assign many to a viewContoller. Simply add all of them to the viewController, give each a different id and then call those id's
if([[splitresponse objectAtIndex:2] isEqualToString:#"yes"])
{
[self performSegueWithIdentifier:#"showParentRegistration" sender:self ];
}
else
{
[self performSegueWithIdentifier:#"showSohoDashboard" sender:self ];
}
Create 2 connection in storyboard from your source view controller to destination view controller (not button). Insert two different identifiers and when the button is pressed do condition and run a segue depends on the condition:
if(CONDITION TO RUN SEGUE !)
{
[self performSegueWithIdentifier:#"SEGUEIDENTIFIER1" sender:self ];
}else {
[self performSegueWithIdentifier:#"SEGUEIDENTIFIER2" sender:self ];
}
I have 2 view controllers, in the first one I make calculations that repeat in an endless loop.
The problem is that I want to close the method and everything related to the first method when presenting the second one. Also I am conforming to MKMapViewDelegate that is triggered everytime that user location changes, where I start a background thread work.
Now when presenting the other view controller, I want to get rid of this and break all the operations that were being executed.
I tried to set the delegates to nil, but when turn back to the first one the methods return and gives crash by saying
"Collection <__NSArrayM: 0x17f9b100> was mutated while being enumerated."
This is the function where I make calculations, the array has too many objects in it and takes about 10 sec to fully check this method.
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self makeCalculations];
});
}
-(void)makeCalculations {
BOOL okClicked = NO;
for(NSDictionary *item in array) {
NSInteger responseCode = [[item objectForKey:#"responseCode"] integerValue];
okClicked = (responseCode > 0);
if (okClicked) {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"title" message:#"message" delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
alert.tag =10;
[alert show];
});
}
}
}
Is there any clue and can you provide me an example or suggestion?
Keep a counter and increment it in the loop. Then use something like:
if(counter % 100 == 0) {
if(self.cancelled) {
self.cancelled = NO;
return;
}
}
Now, just set the cancelled BOOL when you present the new modal.
You don't strictly need the counter, you could just check the flag each time...
I am displaying a UIAlertView to the user with an "OK" button on it, and when the user presses the button I would like my delegate method to perform an action. However currently when the user presses the "OK" button the application crashes with this error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0xb)
Here is my code, the alert view shows fine with the button etc, however as soon as the button is pressed this is the error I am getting. It's almost like a breakpoint but if I click the forward button nothing happens.
//.h
#interface ErrorHandling : NSObject <UIAlertViewDelegate> {
//.m
#define myAlertViewsTag 0
- (void)recivedErrorCode:(int)errorCode MethodName:(NSString *)methodName {
switch (errorCode) {
case 1: {
NSLog(#"ERROR = 1");
message = [[UIAlertView alloc] initWithTitle:#"Error 1:"
message:#"The supplied registration code does exist."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[SVProgressHUD dismiss];
[message show];
}
break;
case 2: {
NSLog(#"ERROR = 2");
message = [[UIAlertView alloc] initWithTitle:#"Error 2:"
message:#"Your registration is no longer valid."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
message.tag = myAlertViewsTag;
[SVProgressHUD dismiss];
[message show];
}
break;
default:
break;
}
}
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (message.tag == myAlertViewsTag) {
if (buttonIndex == 0) {
// Do something when ok pressed
NSLog(#"DONE 1");
} else {
// Do something for ok
NSLog(#"DONE 2");
}
} else {
// Do something with responses from other alertViews
NSLog(#"DONE 3");
}
}
update:
This is how I call the class the code above is in from my conneciton class.
// Do whatever you need to with the error number
ErrorHandling *errorHandling = [[ErrorHandling alloc] init];
[errorHandling recivedErrorCode:errorRecivedFromServerInt MethodName:methodName];
The problem is with the lifetime of your ErrorHandling instance. You create an instance and then call the recivedErrorCode: method. After that there are no other strong references to your errorHandling instance so it gets deallocated.
Meanwhile the alert view has made the instance its delegate. When you tap the button on the alert view, the alert view tries to contact its delegate. But the delegate has been deallocated and now points to garbage memory resulting in the crash.
The solution is to keep a longer lasting strong reference to the ErrorHandling instance. At least until after the alert view is dismissed.
BTW - Your method name has a typo - it should be receivedErrorCode:.
It is not at all clear from this code if this line:
if (message.tag == myAlertViewsTag)...
Actually points to anything valid. Is the message object still around even... I think you problems lies there, somewhere. Post more code that helps us understand this if you want more help.
In alertView:didDismissWithButtonIndex: you are checking the alert view's tag by using "message.tag".
It looks like you were intending for message to be an ivar in your class. A better way that should also solve your bad_access would be to use the alert view that is passed into the didDismissWithButtonIndex, rather than retaining the UIAlertView in your class. This code should do the trick:
-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
if (alertView.tag == myAlertViewsTag) {
if (buttonIndex == 0) {
// Do something when ok pressed
NSLog(#"DONE 1");
} else {
// Do something for ok
NSLog(#"DONE 2");
}
} else {
// Do something with responses from other alertViews
NSLog(#"DONE 3");
}
}