How to display an image using UIView in XCode? - objective-c

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

Related

Subclassed NSTextField generates memory warnings after user input

I have implemented a subclassed version of NSTextField, which I've called CustomTextField, the code for which is below:
#interface CustomTextField : NSTextField
#property (nonatomic, strong) IBInspectable NSImage *backgroundImage;
#end
#implementation CustomTextField
- (void)awakeFromNib
{
[self setDrawsBackground:NO];
}
- (void)drawRect:(NSRect)rect
{
NSImage *backgroundImage = self.backgroundImage;
[backgroundImage drawInRect:rect fromRect:rect operation:NSCompositeSourceOver fraction:1.0];
[super drawRect:rect];
}
#end
I have three instances of this custom text field, which I've set-up in my XIB file. When I run the app, select a text field, type in some text, and hit 'Enter', I get the following output from Xcode:
malloc: protecting edges
malloc: enabling scribbling to detect mods to free blocks
malloc: nano zone does not support guard pages
malloc: purgeable zone does not support guard pages
My guess is that my subclass implementation is not handling something correctly, but I'm honestly not sure. Does anyone have some suggestions? Thanks!
You should call
[super awakeFromNib];
in your awakeFromNib method.
From the docs:
You must call the super implementation of awakeFromNib to give parent
classes the opportunity to perform any additional initialization they
require. Although the default implementation of this method does
nothing, many UIKit classes provide non-empty implementations. You may
call the super implementation at any point during your own
awakeFromNib method.

IBOutlet is nil after initWithCoder is called

Simple problem, I have defined a UIImageView, called bigImageView in a UIViewController using the storyboard,
It's declared in the h file of that UIViewController as follows:
#property (retain, nonatomic) IBOutlet UIImageView *bigImageView;
on my appDelegate I init the UIViewController as follows:
imageViewController = [storyboard instantiateViewControllerWithIdentifier:#"chosenImageController"];
this calls initWithCoder on my UIViewController m file:
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
// Custom initialization
}
return self;
}
This function is only called once so there's no double init.
However, later, when I check my bigImageView pointer, it's still nil.
Isn't the init supposed to allocate memory to it?
I think that's why when I try to set this UIImageview to hold a UIImage it doesn't display the image
Thanks
It's all working how it's meant to. First every object in the nib/storyboard gets alloc/init called on them, then all the connections are made, and then viewDidLoad is called.
You need to wait for - (void)viewDidLoad to be called on your controller, and then bigImageView should be set. If it's not set then you did something wrong in the storyboard.
init methods are not responsible for allocating any memory. All memory is allocated by the alloc method which is always called before init. Alloc will fill all your instance variables with nil/NULL/0 values, and then init gives the chance to assign initial values to each one (based on the contents of the NSCoder object usually, but it's up to you to decide what should be done).
For IB outlets however, those are setup by the nib loading process after init.
EDIT:
// ViewControllerA.m:
imageViewController = [storyboard instantiateViewControllerWithIdentifier:#"chosenImageController"];
imageViewController.image = imageToShow;
// ViewControllerB.h
#property (retain) NSImage *image;
#property (retain, nonatomic) IBOutlet UIImageView *bigImageView;
// ViewControllerB.m
- (void)viewDidLoad
{
self.bigImageView.image = self.image;
[super viewDidLoad];
}
You don't need to define initWithCoder, since you have no custom logic in there. I would delete that boilerplate code.
Here is what I would check:
In the storyboard, ensure that the class of the view controller is set properly.
Ensure that the outlet is hooked up properly in the storyboard by looking for a circle near your #property. It should be a filled in circle, not an outline of a circle.
Make sure you are reading the value only after viewDidLoad is called. Apple's only guarantee is that the outlet is set after this method call.
Update: It sounds like you want to access the image view before the view is loaded. There is no way to do this. One hack is to call viewController.view which will force the view to load, but there are many reasons why you should not do this.
A better approach would be to implement properties on your view controller which work for both when the view is not loaded and when the view is loaded. You can see an example of an elegant solution in this question. Notice how if the view is loaded, the photographerLabel will get set via the didSet method. On the other hand, if the view is not loaded, it will get set via the viewDidLoad method. For an Objective-C version of that code or for more details, see the linked video in that question.

Why won't this code allocate a subView?

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...

Bringing up new view controllers - releasing query

I've written some code where I bring up a new view (from my main view controller); then it calls the main controller when it is closed, like so -
-(void)showMyNewView {
MyNewViewController *myNewViewController = [[MyNewViewController alloc] initWithNibName:#"MyNewViewController" delegate:self];
[self.view addSubview:myNewViewController.view];
}
and then when the new one closes, it calls -
-(void)myNewViewControllerDidFinish:(MyNewViewController *)myNewViewController {
[myNewViewController.view removeFromSuperview];
[myNewViewController release];
}
Now this works fine, and there are no leaks, but the compiler moans with warnings about "Potential leak of an object allocated on line x and stored into myNewViewController".
I've been looking at Apple's presentModalViewController:animated: code, which also doesn't release the new modal view controller in the method which creates it, it seems to release it with a dismissModalViewControllerAnimated: call when the delegate's viewControllerDidFinish: method is called. Is there something I'm missing here? Using the presentModalViewController code doesn't generate any warnings. Many thanks for any help.
I think I've figured it out now, and I've written a small bit of code which gives me my own version of "presentModalViewController:animated:" with all the control I want. I'd be grateful to hear what more seasoned coders make of this (it's probably really straight forward but I've not been doing this for very long...), and if there are any problems with the code, etc -
Interface:
#import <UIKit/UIKit.h>
enum {
MyViewLoaderTransitionTypeNone = 0,
MyViewLoaderTransitionTypeSomeEffect,
MyViewLoaderTransitionTypeSomeOtherEffect
};
typedef NSInteger MyViewLoaderTransitionType;
#interface MyViewLoader : UIViewController {
UIViewController *myLoadedViewController;
}
#property (nonatomic, retain) UIViewController *myLoadedViewController;
-(void)loadView:(UIViewController *)theViewController withTransition:(MyViewLoaderTransitionType)theTransition;
-(void)dismissViewWithTransition:(MyViewLoaderTransitionType)theTransition;
#end
Implementation:
#import "MyViewLoader.h"
#implementation MyViewLoader
#synthesize myLoadedViewController;
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
;
}
return self;
}
-(void)dealloc {
[myLoadedViewController release];
[super dealloc];
}
-(void)loadView:(UIViewController *)theViewController withTransition:(MyViewLoaderTransitionType)theTransition {
[self setLoadedViewController:theViewController];
UIView *theLoadedView = theViewController.view;
[self.view addSubview:theLoadedView];
// do all sorts of transition stuff here
[theViewController viewWillAppear:NO];
}
-(void)dismissViewWithTransition:(MyViewLoaderTransitionType)theTransition {
UIView *theLoadedView = self.loadedViewController.view;
// do all sorts of transition stuff here
[theLoadedView removeFromSuperview];
self.loadedViewController = nil
}
I just use MyViewLoader as the superclass of any view controllers where I need it.
Thanks for any comments / help!
The usual thing to do here is, when you add a subview to a view, release the subview directly after. The parent view becomes responsible for the subview. When removeFromSuperview is called later, that decrements the retain count and the subview is automatically released.

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.