I am making my app compatible to iOS 5 but the app crashes on the code where i have used setContentViewController.
Here is my code.
[[ChoicesViewController sharedChoices] setCurrentValue:[[(UIButton *)sender titleLabel] text]];
[self.choicesPopoverController setContentViewController:[ChoicesViewController sharedChoices]];
CGFloat popoverHeight = 44.0f * [[[ChoicesViewController sharedChoices] choices] count];
[self.choicesPopoverController setPopoverContentSize:CGSizeMake(380.0f, MIN(400.0f, popoverHeight))];
if ([self.choicesPopoverController isPopoverVisible]) {
[self.choicesPopoverController dismissPopoverAnimated:YES];
} else {
[self.choicesPopoverController presentPopoverFromRect:[(UIButton *)sender frame]
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
here is what shared choices returns:
static ChoicesViewController *_sharedChoices = nil;
+(id)sharedChoices
{
if (!_sharedChoices)
{
_sharedChoices = [[[self class] alloc] init];
}
return _sharedChoices;
}
//When i comment the below code , the app wont crash in iOS 5 but the UIPopover is not shown too. And if I uncomment it it will crash in iOS 5.
-(UIPopoverController *)choicesPopoverController
{
if (!choicesPopoverController)
{
choicesPopoverController = [[UIPopoverController alloc] initWithContentViewController:self];
}
return choicesPopoverController;
}
You say you set breakpoints and found this line was the problem :
[self.choicesPopoverController setContentViewController:[ChoicesViewController sharedChoices]];
but there's a few things going on there. Where does it crash if you change that line to
id controller = self.choicesPopoverController;
id shared = [ChoicesViewController sharedChoices];
[controller setContentViewController:shared];
?
Finally i found the solution :
instead of writing
[self.choicesPopoverController setContentViewController:[ChoicesViewController sharedChoices]];
i did
choicesPopoverController = [[UIPopoverController alloc] initWithContentViewController:[ChoicesViewController sharedChoices]];
and commented out the this code
/*
-(UIPopoverController *)choicesPopoverController
{
if (!choicesPopoverController)
{
choicesPopoverController = [[UIPopoverController alloc] initWithContentViewController:self];
}
return choicesPopoverController;
}
*/
Now it doesnt crash in iOS 5.
Related
As I understand from reading documentation, UIPopoverControllers are only supported on the iPad. Therefore if you try to declare a variable as a UIPopoverController and run the app in the iPhone simulator or on an iPhone, you get an error such as:
UIPopoverController initWithContentViewController:] called when not running under UIUserInterfaceIdiomPad
So I have a universal monotouch app I am trying out, where I would like to use a UIPopoverController when the user is using an iPad, for the iPhone I have another solution.
This is how I am declaring it at the moment, but obviously running on the iPhone does not work, and I get the above error message.
public partial class IOPSCalculatorViewController : UIViewController
{
static bool UserInterfaceIdiomIsPhone {
get { return UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone; }
}
static bool UserInterfaceIdiomIsIPAD {
get { return UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad; }
}
UIPopoverController DetailViewPopover = new UIPopoverController(new PopoverContentViewController());
}
How can I only declare the:
UIPopoverController DetailViewPopover = new UIPopoverController(new PopoverContentViewController());
part if the device is an iPad? I need the UIPopoverController to be in the public partial class so that I can access it publically in other places.
Instead of declaring and allocating in one line just split it in two lines. E.g.
UIPopoverController DetailViewPopover = null;
if (IOPSCalculatorViewController.UserInterfaceIdiomIsIPAD) {
DetailViewPopover = new UIPopoverController (new PopoverContentViewController ());
}
That will also work if DetailViewPopover is a (public) field instead of an instance variable and, as long as the UIPopoverController constructor is not invoked, you won't be getting the error.
You need to find out what is your current device and write code for iphone and iPad as well. here is a snap of code that I've used in my case.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
//Do your coding here
}
else {
if(![popoverController isPopoverVisible]){
contact = [[[ContactViewController alloc] initWithNibName:#"ContactViewController_iPad" bundle:nil] autorelease];
popoverController = [[[UIPopoverController alloc] initWithContentViewController:contact] retain];
[popoverController setPopoverContentSize:CGSizeMake(400.0f, 400.0f)];
[popoverController presentPopoverFromRect:CGRectMake(230, 860, 320.0f, 320.0f) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
[popoverController release];
}else{
[popoverController dismissPopoverAnimated:YES];
}
}
hope this will help you. Happy Coding!!!
I have a huge problem, I've integrated inmobi in my app, which doesnt support interface orientation, but when i press on ad, view is loaded on top and it rotates, this wouldn't be bad, but the when it rotates, the view becomes distorted, not covering full screen,
maybe someone has had similar problem?
My code:
- (void)showInMobiBanner
{
if (_inMobView == nil)
{
_inMobView = [[IMAdView alloc] init];
_inMobView.delegate = self; //optional
_inMobView.imAppId = kInMobiAppId;
_inMobView.imAdUnit = IM_UNIT_320x50;
_inMobView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin;
}
if (self.containerView != nil)
{
_inMobView.rootViewController = self.containerView;
}
else
{
_inMobView.rootViewController = self.navigationController;
}
IMAdRequest *request = [IMAdRequest request];
request.isLocationEnquiryAllowed = NO;
_inMobView.frame = CGRectMake(0, 0, 320, 50);
_inMobView.imAdRequest = request;
[_inMobView loadIMAdRequest:request];
[self.view addSubview:_inMobView];
}
Thanks in advance!
It seems you're using an older version of InMobi SDK(3.0.2).
There has been a newer version launched very recently: http://developer.inmobi.com/wiki/index.php?title=IOS_SDK_350
A new method has been introduced:
- (BOOL)shouldRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation;
You can make use of this method in your UIViewController, and tackle orientation changes something like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return [imAdView shouldRotateToInterfaceOrientation:interfaceOrientation];
}
Hope this helps!
Hi
I am adding a "post comment section in my iPhone APP"
rest all things are working fine but when I tap on "postController textView" a keyboard is suppose to appear from the bottom but it is not appearing However the cursor is displaying and the text that I am passing using postController.textView.text = #"" is also displaying.
Please suggest the areas to be looked for fixing this bug.
-(void)showCommentView
{
TTPostController *postController = [[TTPostController alloc] init];
// self must implement the TTPostControllerDelegate protocol
postController.delegate = self;
self.popupViewController = postController;
// assuming self to be the current UIViewController
postController.superController = self;
postController.textView.text=#"temporary text";
[postController showInView:self.view animated:YES];
[postController release];
}
above is the code that is giving call to the Three20 PostController
below is the calling method which is unchanged...
-(IBAction)postComment:(id)sender
{
[UserManager instance]authenticateUserAndProceed:self withSelector:#selector(showCommentView)];
}
-(void)showCommentView
{
TTPostController *postController = [[TTPostController alloc] init];
// self must implement the TTPostControllerDelegate protocol
postController.delegate = self;
self.popupViewController = postController;
// assuming self to be the current UIViewController
postController.superController = self;
postController.textView.text=#"temporary text";
[postController showInView:self.view animated:YES];
[postController release];
}
changed method
-(void)authenticateUserAndProceed:(id)parent withSelector:(SEL)selector
{
theParentViewController = parent;
self.theFunctionToCall = selector;
if(userid == nil)
{
GetUserInfoViewController *guivc = [[GetUserInfoViewController alloc] init];
[parent presentModalViewController:guivc animated:YES];
guivc.delegate = self;
[guivc release];
}
else {
//////////////////// below line was replaced///////////
// 2. [theParentViewController performSelector:selector];
// with below code
UIAlertView *alert =[[UIAlertView alloc]initWith Title........
[alert show];
}
}
PROBLEM SUMMARY:
as soon as the user registered, he was not able to the kyboard for the TTPostController
CHANGE SUMMARY:
As soon as the user is registered the call to
[theParentViewController performSelector:selector];
is not sent directly but the call goes to ann alertview which inter calls it.
EFETCS SUMMARY:
the user will see a "you are registered successfully" (kind of) alertview.
tapping OK on which, he will be sent to TTPostController. (this time the keyboard is appearing)
I kept the line# 2 in the AlertViewDelegate method.
I was amazed o see it working just by not calling the line 2 directly.
this worked for me.
I welcome any new and better idea to implement the same
I had this working very early, but then it stopped and I have no idea why. Here is the code:
- (void)updateMarkers:(NSMutableArray *)myAudioLocationVOArray
{
[self cleanupMarkers];
NSLog(#"UPDATE ALL MARKERS");
int tArrayCount = [myAudioLocationVOArray count];
for (int i=0; i< tArrayCount; i = i + 1)
{
AudioLocationVO* tAudioLocVO = [myAudioLocationVOArray objectAtIndex:i];
AudioAnnotation *tNewAnn = [[AudioAnnotation alloc] init];
tNewAnn.coordinate = CLLocationCoordinate2DMake(tAudioLocVO.latitude, tAudioLocVO.longitude);
// add current track if available
tNewAnn.audioLocationVORef = tAudioLocVO;
[self.mapView addAnnotation:tNewAnn];
[tNewAnn release];
}
}
- (void)cleanupMarkers
{
NSLog(#"REMOVE ALL MARKERS");
NSArray *tExistingPoints = self.mapView.annotations;
if ([tExistingPoints count] > 0)
{
[self.mapView removeAnnotations:tExistingPoints];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)myMapView viewForAnnotation:(id <MKAnnotation>)myAnnotation
{
if ([myAnnotation isKindOfClass:[AudioAnnotation class]])
{
AudioAnnotation *tAnnotation = (AudioAnnotation *)myAnnotation;
MKAnnotationView *tNewMarkerView = [[[MKAnnotationView alloc] initWithAnnotation:tAnnotation reuseIdentifier:nil] autorelease];
if(tAnnotation.audioLocationVORef.state == ANNOTATION_STATE_DROPPING)
{
NSLog(#"ADD DROP MARKER");
[tNewMarkerView setImage:[UIImage imageNamed:#"greenmarker.png"]];
tNewMarkerView.draggable = YES;
}
else
{
NSLog(#"ADD NEW MARKER");
[tNewMarkerView setImage:[UIImage imageNamed:#"newMarker.png"]];
tNewMarkerView.draggable = NO;
}
tNewMarkerView.frame = CGRectMake(tNewMarkerView.frame.origin.x,tNewMarkerView.frame.origin.y,20,26);
tNewMarkerView.canShowCallout = YES;
tNewMarkerView.enabled = YES;
// callout button
UIButton *tButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
tNewMarkerView.rightCalloutAccessoryView = tButton;
// cover art and title/subtitle
UIButton *tCover = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if(tAnnotation.audioLocationVORef.trackVO==nil)
{
tAnnotation.title = #"Drop a Track";
tAnnotation.subtitle = #"Choose a track to drop";
[tCover setImage:[UIImage imageNamed:#"preCover.png"] forState:UIControlStateNormal];
}
else
{
tAnnotation.title = tAnnotation.audioLocationVORef.trackVO.songTitle;
tAnnotation.subtitle = tAnnotation.audioLocationVORef.trackVO.artist;
NSLog(#"ADD DATA MARKER %#", tAnnotation.title);
if(tAnnotation.audioLocationVORef.state==ANNOTATION_STATE_DROPPING){
tAnnotation.subtitle = #"Touch submit to Drop";
}
[tCover setImage:[tAnnotation.audioLocationVORef.trackVO getCoverArt] forState:UIControlStateNormal];
}
// make cover enabled to see song detail?
tCover.enabled = NO;
tNewMarkerView.leftCalloutAccessoryView = tCover;
[tCover release];
return tNewMarkerView;
}
return nil;
}
I tried to delete and add again the graphics as assets. I have been playing around a bit with the frame property. So far no luck.
And why the difference between simulator and device. I am using SDK 4.2... on iPhone 4
Make sure the image filenames match exactly with the resource names including upper/lower-case.
For example, if the resource is "GreenMarker.png", then "greenmarker.png" will only work on the simulator and not on the device.
Apple QA1697 (Why doesn't my device load a file that loads fine in the Simulator?) says:
Case-sensitivity: iPhone OS uses a
case-sensitive file system, unlike the
Simulator which uses a
case-insensitive file system by
default. Make sure the
case-sensitivity of resources accessed
within code matches the filename
case-sensitivity.
True, they should, but the Mac is case-preserving but also case-insensitive. The simulator runs on the Mac, so that's what you get.
I've used a recipe from the iPhone Developer's Cookbook called ModalAlert in order to get some text from a user; however, when the alert is shown, the keyboard and buttons are frozen. Here is the code for the modal alert.
+(NSString *) textQueryWith: (NSString *)question prompt: (NSString *)prompt button1: (NSString *)button1 button2:(NSString *) button2
{
// Create alert
CFRunLoopRef currentLoop = CFRunLoopGetCurrent();
ModalAlertDelegate *madelegate = [[ModalAlertDelegate alloc] initWithRunLoop:currentLoop];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:question message:#"\n" delegate:madelegate cancelButtonTitle:button1 otherButtonTitles:button2, nil];
// Build text field
UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 260.0f, 30.0f)];
tf.borderStyle = UITextBorderStyleRoundedRect;
tf.tag = TEXT_FIELD_TAG;
tf.placeholder = prompt;
tf.clearButtonMode = UITextFieldViewModeWhileEditing;
tf.keyboardType = UIKeyboardTypeAlphabet;
tf.keyboardAppearance = UIKeyboardAppearanceAlert;
tf.autocapitalizationType = UITextAutocapitalizationTypeWords;
tf.autocorrectionType = UITextAutocorrectionTypeNo;
tf.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
// Show alert and wait for it to finish displaying
[alertView show];
while (CGRectEqualToRect(alertView.bounds, CGRectZero));
// Find the center for the text field and add it
CGRect bounds = alertView.bounds;
tf.center = CGPointMake(bounds.size.width / 2.0f, bounds.size.height / 2.0f - 10.0f);
[alertView addSubview:tf];
[tf release];
// Set the field to first responder and move it into place
[madelegate performSelector:#selector(moveAlert:) withObject:alertView afterDelay: 0.7f];
// Start the run loop
CFRunLoopRun();
// Retrieve the user choices
NSUInteger index = madelegate.index;
NSString *answer = [[madelegate.text copy] autorelease];
if (index == 0) answer = nil; // assumes cancel in position 0
[alertView release];
[madelegate release];
return answer;
}
Thanks!
You should probably check whether a UITextField's userInteractionEnabled property defaults to YES or NO.
// Put the modal alert inside a new thread. This happened to me before, and this is how i fixed it.
- (void)SomeMethod {
[NSThread detachNewThreadSelector:#selector(CheckCurrentPuzzle) toTarget:self withObject:nil]; }
-(void) CheckCurrentPuzzle {
NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];
// code that should be run in the new thread goes here
if ([gameBoard AreAllCellsFilled]) {
if ([gameBoard FilledWithoutWin]) {
//only show this message once per puzzle
if (![currentPuzzle showedRemovalMessage]) {
NSArray *buttons = [NSArray arrayWithObject:#"Yes"];
if ([ModalAlert ask:#"blah blah blah" withTitle:#"Incomplete Puzzle" withCancel:#"No" withButtons:buttons] == 1) {
NSLog(#"Remove The Incorrect Cells");
[gameBoard RemoveIncorrect];
} else {
[gameSounds.bloop2 play];
}
}
} else {
if ([gameBoard IsBoardComplete]) {
[self performSelectorOnMainThread:#selector(WINNER) withObject:nil waitUntilDone:false];
}
}
}
[pool2 release];
}
-(void) WINNER {
//ladies and gentleman we have a winner
}
I had a problem similar to this in my educational game QPlus. It bugged me because I had the "exact" same code in two related apps, and they did not have the bug. It turned out that the bug was because the selector method was not declared in the header file. I am working in Xcode 4.2.
Details below:
In .m:
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(emailLabelPressed)];
tapRecognizer.numberOfTapsRequired = 1;
[aLabel addGestureRecognizer:tapRecognizer];
[aLabel setUserInteractionEnabled:YES];
And later in the .m:
(void)emailLabelPressed {
//details
}
That works just fine in the simulator, but on an actual device the email interface presented modally will not edit. You can send or save as draft but no editing.
Then add this to the .h file:
(void)emailLabelPressed;
And voila, it works on the device. Of course this was the difference with the related apps - they both had the method declared in the header file. I would classify this as an iOS bug, but being such a novice developer I wouldn't presume to know.
Based on this, you may want to verify that your selector method moveAlert: is declared in your header file.
Enjoy,
Damien