Why won't this code allocate a subView? - objective-c

This is my code where I'm trying to create a subView... I'm using XCode4 with StoryBoards. The app is crashing on the 2nd line where it is allocating subView with EXC_BAD_ACCESS. vFrame has valid content. What is wrong with this? (I'm using XCode4 with Storyboards, btw).
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect vFrame = CGRectMake(60,100,200,200);
subView = [[UIView alloc] initWithFrame:vFrame];
subView.backgroundColor = [UIColor redColor];
[self.view addSubview: subView];
}
UPDATE: definition for subView:
#interface PreferencesViewController : UIViewController {
UIView *subView;
}
#property (nonatomic, retain) UIView *subView;
#end

That really should work. Was your view controller (PreferencesViewController) properly alloc'd and init'd? Did you #synthesize your subview?
Although it shouldn't matter, you could try using floats for the CGRect (add a .0 to the end of each).

Try moving your sub view instantiation code to the method viewWillAppear of your main view. This guarantees everything has been initialized.

The problem was the UIViewController was farkled...don't know how, but once it was replaced, it worked like a champ! Thank you all for your responses...

Related

Unable to set content in NSPopover

I'm showing an NSPopover in an NSView, originating from a point on an NSBezierPath. I'm able to show the popover without a problem, but I can't seem to set the string value of the two text fields in it. The popover and the content view are both a custom subclass of NSPopover and NSViewController, respectively. The NSPopover subclass is also the NSPopover's delegate, although I don't implement any delegate methods, so I'm not sure I even need to do that.
Here is my subclass of NSViewController:
#import <Cocoa/Cocoa.h>
#interface WeightPopoverViewController : NSViewController
#end
#import "WeightPopoverViewController.h"
#interface WeightPopoverViewController ()
#end
#implementation WeightPopoverViewController
- (id)init {
self = [super initWithNibName:#"WeightPopoverViewController" bundle:nil];
if (self) {
}
return self;
}
#end
And my subclass of NSPopover:
#import <Cocoa/Cocoa.h>
#interface WeightPopoverController : NSPopover <NSPopoverDelegate> {
NSTextField *dateLabel;
NSTextField *weightLabel;
}
#property (strong) IBOutlet NSTextField *dateLabel;
#property (strong) IBOutlet NSTextField *weightLabel;
#end
#import "WeightPopoverController.h"
#implementation WeightPopoverController
#synthesize weightLabel;
#synthesize dateLabel;
#end
This is the code in my NSView subclass that opens up the popover:
#interface WeightGraphViewController () {
WeightPopoverController *popover;
WeightPopoverViewController *vc;
}
...
-(void)mouseEntered:(NSEvent *)theEvent {
// initialize the popover and its view controller
vc = [[WeightPopoverViewController alloc] init];
popover = [[WeightPopoverController alloc] init];
// configure popover
[popover setContentViewController:vc];
[popover setDelegate:popover];
[popover setAnimates:NO];
// set labels
for (id key in (id)[theEvent userData]) {
[popover.weightLabel setStringValue:[(NSDictionary*)[theEvent userData] objectForKey:key]];
[popover.dateLabel setStringValue:key];
}
// set the location
(redacted, irrelevant)
// show popover
[popover showRelativeToRect:rect ofView:[self window].contentView preferredEdge:NSMaxYEdge];
}
-(void)mouseExited:(NSEvent *)theEvent {
[popover close];
popover = nil;
}
In WeightPopoverViewController.xib, I've set the File's Owner to WeightPopoverViewController and connected the view to the custom NSView. In this xib I also have an Object set to WeightPopoverController with the dateLabel and weightLabel connected to their text fields and the contentViewController set to File's Owner.
I think where I am going wrong is likely related to how I have configured my class / instance variables for the NSPopover, but from the research I've done and documentation I've read I can't seem to crack where I've gone wrong. Any help would be appreciated.
UPDATE:
I removed the NSPopover subclass from code and from IB. I put my outlets in my NSViewController and connected them in IB. However, I'm still not able to set the string values. The following won't compile with the error "Property 'weightLabel' not found on object of type NSPopover*'".
#interface WeightGraphViewController () {
NSPopover *popover;
...
}
-(void)mouseEntered:(NSEvent *)theEvent {
vc = [[WeightPopoverViewController alloc] init];
popover = [[NSPopover alloc] init];
[popover setContentViewController:vc];
[popover.dateLabel setStringValue:#"test"];
}
I have the property definition exactly as I had it in my NSPopover subclass, but now in my NSViewController. This is actually what I had before, and since I wasn't able to set the properties from the NSViewController, I figured I needed to do it through a subclass of NSPopover. This is why I thought I am having an issue with how I have configured my class / instance variables.
You seem to be creating two popovers, one in code (popover = [[WeightPopoverController alloc] init]) and one in Interface Builder (In this xib I also have an Object set to WeightPopoverController). Have a think about what you’re trying to achieve.
I would also advise against subclassing NSPopover. I believe this is causing confusion and is unnecessary. Instead, put the outlets to your dateLabel and weightLabel in the popover’s content view controller.
I've experienced something that I think is similar. The root problem is that the "outlets" connecting your view (XIB) to your controller are not initialized until after the view has been displayed. If the controller tries to set properties on any UI controls in the view before the popover has been opened, those changes are ignored (since all the controls will be nil).
Luckily, there's an easy solution (as mentioned in this answer): just invoke the view getter on your controller, and it will force the view to initialize sooner.
In other words:
popover = [NSPopover new];
myController = [[MyViewController alloc] initWithNibName:#"MyView" bundle:nil];
popover.contentViewController = myController;
[myController view]; // force view to initialize
...set some values on myController... // works because view is now loaded
[popover showRelativeToRect: ...];

How do I access or manipulate variables of one class from another in Xcode

I am a novice to IOS programming hence struggling a bit with the below problem. I will do my best to describe the problem and any help is greatly appreciated.
I have the following created:
AboutViewController (.h, .m and .xib ) which has two subviews called - mainView, infoView. mainView and infoView interfaces are created in the XIB file.
TestView ( View to deal with initiating, toggling between mainView and infoView )
TestView.h is as follows:
#interface TestView : UIView {
IBOutlet UIView *mainView;
IBOutlet UIView *infoView;
UILabel *lbltitle;
UIImageView *imgIcon;
IBOutlet UITextView *txtInfo1;
IBOutlet UITextView *txtInfo2;
IBOutlet UITextView *txtInfo3;
}
#property (nonatomic, retain) IBOutlet UILabel *lbltitle;
#property (nonatomic, retain) IBOutlet UIImageView *imgIcon;
TestView.m is as follows:
#import "TestView.h"
#import <QuartzCore/QuartzCore.h>
#implementation TestView
#synthesize lbltitle, imgIcon;
-(void)awakeFromNib
{
[self addSubview:mainView];
}
In portrait mode the views are working great but when it comes to landscape mode, the views are all kinda screwed up. I tried to use the XIB but I guess you can only do so much so I decided to do this programmatically.
In the AboutViewController.m, I am trying to override willAnimateRotationToInterfaceOrientation method and place the objects based on the orientation. When I put breakpoints, I can see that code is being called except it is not translating into the UI i.e., no change in the UI. What am I doing wrong ? Should I be approaching this in a different way. Any suggestions or guidance is greatly appreciated.
- (void)willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
TestView *t = [[TestView alloc]init];
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
[t.imgIcon setFrame:CGRectMake(10,74,165,190)];
[t.lbltitle setFrame:CGRectMake(20, 10, 387, 21)];
}
else
{
[t.imgIcon setFrame:CGRectMake(10,74,165,190)];
[t.lbltitle setFrame:CGRectMake(189, 10, 387, 21)];
}
}
Well the particular problem is you manipulate a view that you just created using
TestView *t = [[TestView alloc]init];
You don't display the view anywhere, so it sits in memory. You can apply all changes you want, but to be able to see them, you must first display the view:
Find the appropriate parent and do:
[parentview addSubview:t];
In more general terms you shouldn't be creating new views in the rotation handling code.

How to display an image using UIView in XCode?

Absolutely beginner question. I am trying to make an app which will switch an array of images by swiping the screen sideways. So, as vanilla case of that I was trying to display an image first and then think about how to switch between images using an action. I am using XCode 4.2.
So, here's what I have so far. I have added a UIImageView to my storyboard, then Ctrl+dragged into the ".h" file to create an Outlet and it looks something like this:
SwitchViewController.h
#import <UIKit/UIKit.h>
#interface SwitchViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#end
And then in the ".m" file, I am trying to set an image to the UIImageView in the DidLoad method.
SwitchViewController.m
#import "SwitchViewController.h"
#implementation SwitchViewController
#synthesize imageView;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIImage *plate1 = [UIImage imageNamed:#"plates1.tif"];
[imageView setImage:plate1];
}
- (void)viewDidUnload
{
[self setImageView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ((interfaceOrientation == UIInterfaceOrientationLandscapeRight) ||
(interfaceOrientation == UIInterfaceOrientationLandscapeLeft))
return YES;
return NO;
}
#end
Now, if I try to run this, there are no compilation errors. But the program halts saying, Thread 1:Program received signal "SIGABRT"
Referring to your actual problem, you're getting this exception being thrown:
2012-01-26 22:04:40.728 Switch-a-Switch[548:f803] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<SwitchViewController 0x6840660> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key UIImageView.'
It would appear that you've wired up the UIImageView to a property called UIImageView rather than imageView. Go and redo the connection in Interface Builder and make sure you drag from the imageView property to your UIImageView instance.
UIImage *plate1 = [UIImage imageNamed:#"plates1.tif"];
[imageView setImage:plate1];
should be kosher in iOS and 64 Bit (non-fragile ABI environments, as the iVar will be synthesized), I think it is much better form to include the ivar in the interface....
#interface SwitchViewController : UIViewController
{
UIImageView *imageView;
}
The thing that you should do to track this down is to turn on zombies and enable an exception breakpoint.
afew things there. (now im only learning myself so may be wrong but here goes)
when you use the #property u should use the self.imageView setter to assign to it. so [imageView setImage:plate1] would become self.imageView.image = plate1. and change it from weak to retain in the .h. and in the viewdidunload do self.imageView = nil. also i think the swiping of images effect your trying to achieve here might be better suited to a horizontal scrollview. and u can turn on paging or something for that.
hope that helps and didnt send u completely wrong direction :P
I think you may be going about this the wrong way. If you want to side swip to go between images, you should use a UIScrollView with paging enabled. A quick google came up with this.
Hope that helps

adding UIImageView to UIScrollView throws exception cocoa touch for iPad

I am a noob at OBJ-C :)
I am trying to add a UIImageView to a UIScrollView to display a large image in my iPhone app.
I have followed the tutorial here exactly:
http://howtomakeiphoneapps.com/2009/12/how-to-use-uiscrollview-in-your-iphone-app/
The only difference is that in my App the View is in a seperate tab and I am using a different image.
here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Cheyenne81"]];
self.imageView = tempImageView;
[tempImageView release];
scrollView.contentSize = CGSizeMake(imageView.frame.size.width, imageView.frame.size.height);
scrollView.maximumZoomScale = 4.0;
scrollView.minimumZoomScale = 0.75;
scrollView.clipsToBounds = YES;
scrollView.delegate = self;
[scrollView addSubview:imageView];
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return imageView;
}
and:
#interface UseScrollViewViewController : UIViewController<UIScrollViewDelegate>{
IBOutlet UIScrollView *scrollView;
UIImageView *imageView;
}
#property (nonatomic, retain) UIScrollView *scrollView;
#property (nonatomic, retain) UIImageView *imageView;
#end
I then create a UIScrollView in Interface Builder and link it to the scrollView outlet. Thats when I get the problem. When I run the program it crashes instantly.
If I run it without linking the scrollView to the outlet, it will run (allbeit with a blnk screen).
The following is the error I get in the console:
2010-03-27 20:18:13.467 UseScrollViewViewController[7421:207] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIViewController 0x4a179b0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key scrollView.'
Try to add
#synthesize imageView;
into the #implementation of UseScrollViewViewController.
As there was no accepted answer solving the problem I figured I post my answer which solved my similar problem.
As tab bar is being used, you should also check the Tab Bar Controller's attributes in IB. Most probably the type for your view controller (which is under Tab Bar Controller item, which is I guess in MainWindow.xib) is UIViewController. Change it to your specific controller.
First, the obligatory "the iPad SDK is still under NDA, so you shouldn't be posting this question here, and we can't help you" response.
Now If this were and iPhone app I would say check in the interface builder: click on "File's owner" and in the inspector, make sure that the class is set to be the class you are using to load the nib.

Why isn't my UIButton responding to touches?

I'm sure I'm overlooking the obvious as I've got countless working buttons...but...for whatever reason this one is not cooperating...
I've added a UIButton (Rounded Rect) to a UIView subclass (DialogView) which is a subview of my view controller's view. This subview is created almost entirely in IB. I've wired up the button to (IBAction)okButtonPressed:(id)sender in IB to Touch Up Inside and created a corresponding method in DialogView. However when I "touch" this button it doesn't trigger the method. userInteractionEnabled is true for the VC's view, DialogView and the UIButton.
Thinking maybe initWithCoder had to do some frame manipulation or something I added the following which successfully logs to console.
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super initWithCoder:decoder]) {
NSLog(#"DialogView initWithCoder called");
}
return self;
}
In further exploration I wired up an IBOutlet to the button and then if I try to change the titleLabel from the view controller I notice that it get's severely truncated. Default text of say "Press Me!" set in IB displays fine when view is first drawn. But if I change the text...
self.DialogView.okButton.titleLabel.text = #"Not Working";
...it gets truncated to "N..."
Dunno if this is related. Probably...
Anyone see what I've screwed up here?
Edit (adding code related to showing UIButton):
From the View Controller:
self.DialogView = [[[NSBundle mainBundle] loadNibNamed:#"DialogView" owner:self options:nil] objectAtIndex:0];;
self.DialogView.myVC = self;
self.DialogView.backgroundColor = [UIColor clearColor];
self.DialogView.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
self.DialogView.nameLabel.text = loan.fullName;
self.DialogView.noteLabel.text = loan.summaryOfLoan;
self.DialogView.amountLabel.text = [currencyFormatter stringFromNumber:loan.originalAmount];
self.DialogView.alpha = 0.0;
[self.view addSubview:DialogView];
The UILabels all displaying as expected. As is the problem UIButton. I can see it I just can't interact with it!?!
DialogView's interface:
#class MyViewController;
#interface DialogView : UIView {
IBOutlet UILabel *nameLabel, *noteLabel, *amountLabel;
IBOutlet UIImageView *arrowView;
IBOutlet UIButton *okButton;
MyViewController *myVC;
}
#property (nonatomic, retain) UILabel *nameLabel, *noteLabel, *amountLabel;
#property (nonatomic, retain) UIImageView *arrowView;
#property (nonatomic, assign) MyViewController *myVC;
#property (nonatomic, retain) UIButton *okButton;
- (IBAction)okButtonPressed:(id)sender;
#end
And DialogView's implementation:
#import "DialogView.h"
#import "MyViewController.h"
#implementation DialogView
#synthesize nameLabel, noteLabel, amountLabel, arrowView, okButton;
#synthesize myVC;
- (void)dealloc {
[nameLabel release];
[noteLabel release];
[amountLabel release];
[arrowView release];
[okButton release];
[super dealloc];
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super initWithCoder:decoder]) {
NSLog(#"DialogView initWithCoder called");
}
return self;
}
- (IBAction)okButtonPressed:(id)sender {
NSLog(#"pressed DialogView OK button");
[self.myVC.navigationController popViewControllerAnimated:YES];
}
- (void)drawRect:(CGRect)rect {
// Drawing code
}
#end
I thought that we should use -setTitle:forState: in order to set button's title ?
An other thought, did you check that the button's frame is not CGRectZero ? And by the way, all the frames for the view in the hierarchy ? And check that one superview in the hierarchy is not user interaction disabled ?
And, I think imageView does not respond to touches, do you have one in your code ?
I was just having more or less the same problem and I found that my containing view did not have "User Interaction Enabled".
Hope this helps.
Do you maybe have two buttons on top of one another? Change the IB project window to the detail view and see if your view has more buttons than you are expecting. Maybe you've wired up a button that's not actually getting the press you're expecting.