UIPopoverController trouble - objective-c

I'm trying to create a popover with the following code:
//.h
#interface LoginViewController : UIViewController <UIPopoverControllerDelegate>
....
#end
//.m
- (IBAction)popoverTest:(id)sender
{
UIViewController *popoverContent = [[UIViewController alloc] init];
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
UILabel *nameLabel = [[UILabel alloc] init]; //edited, fixed UILabel allocation
nameLabel.text = #"Person's name";
[nameLabel sizeToFit];
nameLabel.frame = CGRectMake(10, 10, nameLabel.frame.size.width, nameLabel.frame.size.height);
[myView addSubview:nameLabel];
popoverContent.view = myView;
popoverContent.contentSizeForViewInPopover = CGSizeMake(300, 300);
UIPopoverController *popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverContent];
popoverController.delegate = self;
[popoverController presentPopoverFromRect:((UIButton *)sender).frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
NSLog(#"ran all code");
}
I created a UIView, put a label as a subview and then assigned my view to the UIViewController.view. Then I created a popover controller, sized the popover controller, set the delegate and presented it from the button's frame.
I receive a SIGABRT and the app crashes.
Is there something I'm missing?
EDIT: I fixed the UILabel allocation. The problem is always there.

Your code is quite strange.
For example why do you create a view and do you add it to the content view of your popover?
Then, you have to make attention to memory leaks. There a lot of them in your code.
That said, here a simple example for display a UIViewcontroller within a UIPopoverController.
- (IBAction)yourAction:(id)sender
UIButton* senderButton = (UIButton*)sender;
UIViewController* yourController = [[UIViewController alloc] init];
UIPopoverController* pop = [[UIPopoverController alloc] initWithContentViewController:yourController];
pop.delegate = self;
pop.popoverContentSize = CGSizeMake(300, 300);
self.popover = pop;
[pop presentPopoverFromRect:senderButton.bounds inView:senderButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
pop.passthroughViews = nil;
[yourController release];
[pop release];
}
where self.popover is a #property with a retain policy. In this manner in UIPopoverControllerDelegate methods (or wherever you want), you can release your popover and/or dismiss it.
Hope it helps.
P.S. Check the code because I've written by hand.
Edit
Usually when you create a popover, its content view controller is or a custom UIViewController or a UINavigationController (in this case you want to take advantage of its navigation bar).
For example, instead of the simple UIViewController, you could create a custom one
//.h
#interface CustomUIViewController : UIViewController
#end
//.m
#implementation CustomUIViewController
// other code here...
- (void)viewDidLoad
{
// here you are sure that the view has been loaded in memory (alternatively override loadView method), so
UIView* greenView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
green.backgroundColor = [UIColor greenColor];
[self.view addSubview:greenView];
[greenView release];
}
#end
and use it within a a popover
- (IBAction)yourAction:(id)sender
UIButton* senderButton = (UIButton*)sender;
CustomUIViewController* yourController = [[CustomUIViewController alloc] init];
// same as before...
}

solved my issue from this question.
short answer: ARC doesn't retain the UIPopoverController.
i made it an instance variable and works just fine.

The problem seems to be the following:
UILabel *nameLabel;
nameLabel.text = #"Person's name";
nameLabel is uninitialized. It points to random memory, and when calling -setText: through the text-property, your application crashes.
Apart from this, you have a few memory leaks. Remember: If you call alloc, you have to release it somewhere.
(I'm not sure how this works with the new automatic alloc/release).

Related

UIButton - Not clickable in subview [duplicate]

In my .m file I added:
#property (strong, nonatomic) UIImageView *star1;
Then in a method I did:
UIImage *star1Image;
star1Image = [UIImage imageNamed:#"staryes"];
self.star1 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
self.star1.tag = 800;
[self.star1 setImage:star1Image];
[ratingLabelBody addSubview:self.star1];
After a few lines not related to this I have:
[self.star1 setUserInteractionEnabled:YES];
UITapGestureRecognizer *tapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imgTouchUp:)];
tapped.numberOfTapsRequired = 1;
[self.star1 addGestureRecognizer:tapped];
And finally in the .m file I have implemented:
-(void)imgTouchUp:(id)sender {
NSLog(#"imgTouchUp");
UITapGestureRecognizer *gesture = (UITapGestureRecognizer *)sender;
NSLog(#"tap detected on %li", (long)gesture.view.tag);
}
With all this, it should recognize the tap on my image but nothing is happening. Any idea?
So, since components like UILabel or UIImageView aren't design to be "touchable", to add a "touchable" feature (like a UITapRecognizer), you have to set their userInteractionEnabled to YES.
So, even if you set this property correctly for your UIImageView (star1), since you add it as a subview of ratingLabelBody, you couldn't trigger your UITapGestureRecognizer (imgTouchUp:).
You have to do the same to the parent view of your star1, which is ratingLabelBody.
Translated with code, you just had to do:
[ratingLabelBody setUserInteractionEnabled:YES];

Unable to set rightview or leftview in textfield of searchbar in ios 7

Purpose:
I want to set right view as label in searchbar's textfield
Following Code working fine in ios 6 for doing the same thing:
UISearchBar *search = [[UISearchBar alloc] init];
[search setTintColor:[UIColor grayColor]];
search.frame = CGRectMake(0, 150, 320,50);
search.delegate = self;
UITextField *searchField=[search.subviews objectAtIndex:1];//Changed this line in ios 7
searchField.backgroundColor=[UIColor redColor];
UILabel *label=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
label.text=#"Hello";
label.textColor=[UIColor greenColor];
searchField.rightView = label;
searchField.rightViewMode = UITextFieldViewModeAlways;
[self addSubView:search];
When i have Run the same code in ios 7(with xcode 7.0.2 fully updated), It was giving me error, after googling i got that hiearchy of searchbar to textfield has been changed, so i have modified my code as:
replaced commented line in above code with:
UITextField *searchField=[((UIView *)[search.subviews objectAtIndex:0]).subviews lastObject];
after doing this, it is not giving me any error(also checked the logs by printing the description of textfield and everything is working good), when i run it, it gives textfield with red background but the rightView's label is not shown to me. Now, can anyone help me how to show this rightview.
If you want to do this programatically then you have to declare UISearchBar object in your .h file.
UISearchBar *searchBar;
And in your .m file you can code like:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
searchBar = [[UISearchBar alloc] init];
[searchBar setTintColor:[UIColor grayColor]];
searchBar.frame = CGRectMake(0, 150, 320,50);
searchBar.delegate = self;
[self.view addSubview:searchBar];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UITextField *searchField;
if ([[[UIDevice currentDevice] systemVersion] floatValue]<7.0)
searchField=[searchBar.subviews objectAtIndex:1];
else
searchField=[((UIView *)[searchBar.subviews objectAtIndex:0]).subviews lastObject];
searchField.backgroundColor=[UIColor redColor];
UILabel *label=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
label.text=#"Hello";
label.textColor=[UIColor greenColor];
searchField.rightView = label;
searchField.rightViewMode = UITextFieldViewModeAlways;
}
I think this will work for both iOS7 and prior versions of iOS7.
First of all, your approach is not good and not maintainable across iOS versions.
I think that initialization of UISearchBarTextField's right view is taking place after you set your custom view to it's rightView property. You will see correct result if you set searchField.rightView in viewDidAppear method:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UITextField *searchField=[((UIView *)[_searchBar.subviews objectAtIndex:0]).subviews lastObject];
UILabel *label=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
label.text=#"Hello";
label.textColor=[UIColor greenColor];
searchField.rightView = label;
searchField.rightViewMode = UITextFieldViewModeAlways;
}
I've tested it on iOS 7 simulator and it works.
You have to get the text field first.
No need to index subviews to get text field or bar button.
You can directly get the text field and bar button
In swift
let textField = searchBar.valueForKey("searchField") as? UITextField
let cancelBarButton = searchBar.valueForKey("cancelBarButtonItem") as? UIBarButtonItem
In Objective-C
UITextField *textField = [searchBar valueForKey:#"searchField"]:
UIBarButtonItem *cancelBarButton = [searchBar valueForKey:#"cancelBarButtonItem"]:
Then you can set the left view and right view with
textField.leftView = yourView
textField.rightView = yourView

Touch on ImageView to another ViewController

I have 2 ViewControllers and I create one UIImageView to show like Splash Screen on IPhone. I write it in TestAppDelegate.m :
====================
splashScreen = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
splashScreen.image = [UIImage imageNamed:#"Default.png"];
[self.window addSubview:splashScreen];
sleep(6);
[splashScreen removeFromSuperview];
====================
My question is,
if I touch on this imageview I will go to 2nd ViewController.
else after time sleep, automatically to 1st ViewController.
So, it's possible to do that ?
Do this:
Add UIGestureRecognizerDelegate in appDelegate.h file.
#interface AppDelegate : UIResponder <UIApplicationDelegate,UIGestureRecognizerDelegate>
Now
splashScreen = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
splashScreen.userInteractionEnabled = YES;
splashScreen.image = [UIImage imageNamed:#"Default.png"];
UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
tapRecognizer.numberOfTapsRequired = 1;
tapRecognizer.numberOfTouchesRequired = 1;
tapRecognizer.delegate = self;
[splashScreen addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
[self.window addSubview:splashScreen];
sleep(6);
[splashScreen removeFromSuperview];
//add ViewController1 here
ViewController1 *objViewController1 = [[ViewController1 alloc]initWithNibName:#"ViewController1" bundle:nil];
[self.window addSubview:objViewController1.view];
Now handler will be called when tapped on splash screen
- (void)handleTap:(UITapGestureRecognizer*)recognizer
{
// Do Your thing.
if (recognizer.state == UIGestureRecognizerStateEnded)
{
[splashScreen removeFromSuperview]; //edited here
ViewController2 *objViewController2 = [[ViewController2 alloc]initWithNibName:#"ViewController2" bundle:nil];
[self.window addSubview:objViewController2.view];
}
}
Yes. It's possible.In AppDelegate keep NSTimer.
In the selector of timer write code to push to the 1st view controller.
And put a Touch Recognizer on the imageview and on the touch event write code to push to the 2nd View Controller.

UIView in front of everything not rotating with screen?

I have this code:
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
imageView.image = [UIImage imageNamed:#"image.png"];
UIApplication *app = [UIApplication sharedApplication];
[app addSubViewOnFrontWindow:imageView];
...
- (void)addSubViewOnFrontWindow:(UIView *)view {
int count = [self.windows count];
UIWindow *w = [self.windows objectAtIndex:count - 1];
[w addSubview:view];
}
The problem is, when the app rotates, the view on the front doesn't rotate. It just stays in portrait.
How can I get this to rotate normally with the rest of the device?
I haven't tried this, but UIWindow has a property rootViewController
The root view controller for the window.
#property(nonatomic, retain) UIViewController *rootViewController
Discussion
The root view controller provides the content view of the
window. Assigning a view controller to this property (either
programmatically or using Interface Builder) installs the view
controller’s view as the content view of the window. If the window has
an existing view hierarchy, the old views are removed before the new
ones are installed.
The default value of this property is nil.
Availability
Available in iOS 4.0 and later.
Declared In
UIWindow.h
As you should be providing this root view controller you should be able to add it to the rootViewContoller's view, and handle aout rotation correctly.
another solution could be, that you swap the windo with a custom one while presenting your view, with another view controller. this trick in action you can see in the implementation of TSAlertView.
- (void) show
{
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:[NSDate date]];
TSAlertViewController* avc = [[[TSAlertViewController alloc] init] autorelease];
avc.view.backgroundColor = [UIColor clearColor];
// $important - the window is released only when the user clicks an alert view button
TSAlertOverlayWindow* ow = [[TSAlertOverlayWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];
ow.alpha = 0.0;
ow.backgroundColor = [UIColor clearColor];
ow.rootViewController = avc;
[ow makeKeyAndVisible];
// fade in the window
[UIView animateWithDuration: 0.2 animations: ^{
ow.alpha = 1;
}];
// add and pulse the alertview
// add the alertview
[avc.view addSubview: self];
[self sizeToFit];
self.center = CGPointMake( CGRectGetMidX( avc.view.bounds ), CGRectGetMidY( avc.view.bounds ) );;
self.frame = CGRectIntegral( self.frame );
[self pulse];
if ( self.style == TSAlertViewStyleInput )
{
[self layoutSubviews];
[self.inputTextField becomeFirstResponder];
}
}
with
#interface TSAlertOverlayWindow : UIWindow
{
}
#property (nonatomic,retain) UIWindow* oldKeyWindow;
#end
#implementation TSAlertOverlayWindow
#synthesize oldKeyWindow;
- (void) makeKeyAndVisible
{
self.oldKeyWindow = [[UIApplication sharedApplication] keyWindow];
self.windowLevel = UIWindowLevelAlert;
[super makeKeyAndVisible];
}
- (void) resignKeyWindow
{
[super resignKeyWindow];
[self.oldKeyWindow makeKeyWindow];
}
//
#end
add a new window, with new rootviewController, and subscribe it to
[[NSNotificationCenter defaultCenter] addObserver:(id) selector:(SEL) name:UIDeviceOrientationDidChangeNotification object:nil];
Windows don't autorotate. Ever. You should be adding this imageView to a UIViewController's view as the UIViewController has built in autorotation.
If you want to use a UIWindow to hold all your views, you will need to write your own transform code to handle rotations.

How to perform a [self.view addSubview: lbl] outside of ViewController Class scope?

How to perform a [self.view addSubview: lbl] outside of ViewController Class scope ?
or:
How do I add a label or another view in the mainview, outside of the ViewController class, in a different class?
thanks
- (void)viewDidLoad {
[super viewDidLoad];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[lbl setText:#"hi there"];
[self.view addSubview:lbl];// <-- this works, but ...
// what is "self" referring to?
// and how can I declare and call from another class?
...
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[lbl setText:#"hi there"];
calcRomanAppDelegate *v = [[calcRomanAppDelegate new] init];
[v.viewController.view addSubview:lbl]; // this compiles, but...
// fails to shows a label on the form
...
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[lbl setText:#"hi there"];
calcRomanViewController *v = [[calcRomanViewController new] init];
[v.view addSubview:lbl]; // this just makes a call back to viewDidLoad... endless loop
}
Well, view is just a property of the UIViewController class. Assuming that you have your UIViewController *controller variable somewhere, you can just use
[controller.view addSubview:subview]
The reason that [v.viewController.view addSubview:lbl]; doesn't work is that v is a new instance of calcRomanAppDelegate. Every application has a shared instance of the app delegate, that can be accessed via [[NSApplication sharedApplication] delegate]. Therefore, your code would become:
calcRomanAppDelegate *v = (calcRomanAppDelegate *)[[NSApplication sharedApplication] delegate];
[v.viewController.view addSubview:lbl]; // this compiles but shows a blank form
Also In the code that you wrote, I will point out that the new method returns an initialized object, so you do not need the extra call to init in [[calcRomanAppDelegate new] init]. Instead of using the new method, I suggest using alloc, which doesn't call the initializer. Obviously that is not the issue in this particular case, but it's an important thing to know.
Not sure what you tried to accomplish.
But let's say you are in the view1 and want to create another view (view2) with your UILabel lbl added to this view2. Here are what you would do:
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(x, y, w, h)]; //x,y, w h are for your view2
[view addSubview:lbl];
[self.view addSubview:view2]; //self is your current viewcontroller - you add view2 on top of view1
On the other hand if you already have a ViewController class ViewController2.h, ViewController2.m and a ViewController2.xib defined. Here are what you would do:
ViewController2 *viewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
[viewController2.view addSubview:lbl];
[self.view addSubview:viewController2.view]; //same as before, you need to add viewController2's view to the current view
Hope this help.