I am writing a program with a UIImageView. However, I am running into the error: Exc_Arithmetic.
Here is my implementation:
#import "SalaatAppViewController.h"
#implementation SalaatAppViewController
#synthesize imageView;
#synthesize pauseButton;
#synthesize playButton;
#synthesize nextButton;
-(IBAction)pushPauseButton {
[imageView stopAnimating];
}
-(IBAction)pushPlayButton {
[imageView startAnimating];
}
- (IBAction)pushNextButton {
imagesIndex = (imagesIndex + 1) % [images count];
imageView.image = [images objectAtIndex:imagesIndex];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
imageView.animationImages = [[NSArray arrayWithObjects:
[UIImage imageNamed:#"1.png"],
[UIImage imageNamed:#"2.png"],
[UIImage imageNamed:#"3.png"],
nil] retain];
UIImage *image = [UIImage imageNamed: #"2.png"];
[imageView setImage:image];
imageView.animationDuration = 1.00;
imageView.animationRepeatCount = 0;
[imageView startAnimating];
imagesIndex = 0;
imageView.image = [images objectAtIndex:imagesIndex];
[super viewDidLoad];
[self.view addSubview:imageView];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(void) dealloc {
[imageView release];
[pauseButton release];
[playButton release];
[nextButton release];
[super dealloc];
}
#end
My Header:
#import <UIKit/UIKit.h>
#interface SalaatAppViewController : UIViewController {
UIImageView *imageView;
UIButton *pauseButton;
UIButton *playButton;
UIButton *nextButton;
NSUInteger images;
NSUInteger imagesIndex;
}
#property (nonatomic, retain) IBOutlet UIImageView *imageView;
#property (nonatomic, retain) IBOutlet UIButton *pauseButton;
#property (nonatomic, retain) IBOutlet UIButton *playButton;
#property (nonatomic, retain) IBOutlet UIButton *nextButton;
-(IBAction)pushPauseButton;
-(IBAction)pushPlayButton;
-(IBAction)pushNextButton;
#end
The program runs, but with 9 warnings and 1 error. Also, when I push the Next Button, it crashes. Please Help!
The exception indicates that you tried to divide by 0. This expression does a modulus (%) function which returns remainder after division, probably [images count] is 0:
imagesIndex = (imagesIndex + 1) % [images count];
Ahmad your "images" property should be not NSUInteger but NSArray*. Define it in a following way:
NSArray *images;
It seems you replaced too much by following my previous guidance. =)
You never initialize images. Also, as you're calling the count method, it seems that it should be an NSArray and not an NSUInteger.
Related
Every selectedSegmentIndex add different view controller.
On first segmentindex click, present new viewcontroller and second segment index, present another viewcontroller.
and segment control only show bottom.(not add in navigation bar).
segmentcontrol as it is visible every view controller(like tab bar controller).
my problem is that when new controller pop up segment controller disable.
Need help in getting this done.
Try this code
in .h file add
import
#interface SegmentManagingViewController : UIViewController <UINavigationControllerDelegate> {
UISegmentedControl * segmentedControl;
UIViewController * activeViewController;
NSArray * segmentedViewControllers;
IBOutlet UILabel *theLabel;
IBOutlet UIImageView *image;
}
//-(void)setTextColorsForSegmentedControl:(UISegmentedControl*)segmented;
#property (nonatomic, retain, readonly) IBOutlet UISegmentedControl * segmentedControl;
#property (nonatomic, retain, readonly) UIViewController * activeViewController;
#property (nonatomic, retain, readonly) NSArray * segmentedViewControllers;
#end
in .m file add
#import "SegmentManagingViewController.h"
#import "CategoryViewController.h"
#import "AtoZViewController.h"
#interface SegmentManagingViewController ()
#property (nonatomic, retain, readwrite) IBOutlet UISegmentedControl * segmentedControl;
#property (nonatomic, retain, readwrite) UIViewController * activeViewController;
#property (nonatomic, retain, readwrite) NSArray * segmentedViewControllers;
- (void)didChangeSegmentControl:(UISegmentedControl *)control;
- (NSArray *)segmentedViewControllerContent;
#end
#implementation SegmentManagingViewController
#synthesize segmentedControl, activeViewController, segmentedViewControllers;
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title =#"Breadworks";
//self.navigationItem.
[image release];
theLabel = [[UILabel alloc] initWithFrame:CGRectMake(140,-40,180,60)];
theLabel.backgroundColor = [UIColor colorWithRed:120.0f/255.0f green:69.0f/255.0f blue:53.0f/255.0f alpha:1.0f ];
[theLabel setFont:[UIFont fontWithName:#"Noteworthy " size:15]];
//[self.view addSubview:theLabel];
self.segmentedViewControllers = [self segmentedViewControllerContent];
//self.navigationController.navigationBarHidden=YES;
NSArray * segmentTitles = [self.segmentedViewControllers arrayByPerformingSelector:#selector(title)];
self.segmentedControl = [[UISegmentedControl alloc] initWithItems:segmentTitles];
self.segmentedControl.tintColor = [UIColor colorWithRed:255.0f/255.0f green:252.0f/255.0f blue:235.0f/255.0f alpha:1.0f];
self.navigationController.navigationBar.tintColor = [UIColor colorWithRed:120.0f/255.0f green:69.0f/255.0f blue:53.0f/255.0f alpha:1.0f ];
self.segmentedControl.frame=CGRectMake(0,0,768, 73);
self.segmentedControl.selectedSegmentIndex = 0;
self.segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
//self.navigationController.navigationBar.frame = CGRectMake(0, 0,760, 100);
[self.segmentedControl addTarget:self
action:#selector(didChangeSegmentControl:)
forControlEvents:UIControlEventValueChanged];
self.view.frame = CGRectMake(0,4,330, 53);
self.view.backgroundColor = [UIColor colorWithRed:255.0f/255.0f green:252.0f/255.0f blue:235.0f/255.0f alpha:1.0f];
[segmentedControl setTitle:#"1" forSegmentAtIndex:0]
[segmentedControl setTitle:#"2" forSegmentAtIndex:1];
[self.view addSubview:segmentedControl];
[self.segmentedControl release];
[self didChangeSegmentControl:self.segmentedControl]; // kick everything off
}
- (NSArray *)segmentedViewControllerContent {
UIViewController * controller1 = [[CategoryViewController alloc] initWithParentViewController:self];
UIViewController * controller2 =[[AtoZViewController alloc] initWithParentViewController:self] ;
NSArray * controllers = [NSArray arrayWithObjects:controller1, controller2, nil];
[controller1 release];
[controller2 release];
return controllers;
}
#pragma mark -
#pragma mark Segment control
- (void)didChangeSegmentControl:(UISegmentedControl *)control {
if (self.activeViewController) {
[self.activeViewController viewWillDisappear:NO];
[self.activeViewController.view removeFromSuperview];
[self.activeViewController viewDidDisappear:NO];
}
//self.segmentedControl.frame=CGRectMake(5,4,300, 50);
self.activeViewController = [self.segmentedViewControllers objectAtIndex:control.selectedSegmentIndex];
[self.activeViewController viewWillAppear:NO];
[self.view addSubview:self.activeViewController.view];
[self.activeViewController viewDidAppear:NO];
NSString * segmentTitle = [control titleForSegmentAtIndex:control.selectedSegmentIndex];
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:segmentTitle style:UIBarButtonItemStylePlain target:nil action:nil];
/*if(self.segmentedControl.selectedSegmentIndex == 0)
{
segmentedControl.tintColor = [UIColor colorWithRed:255.0f/255.0f green:252.0f/255.0f blue:235.0f/255.0f alpha:10.0f];
}
else
{
//self.segmentedControl.tintColor = [UIColor redColor];
}*/
}
#pragma mark -
#pragma mark View life cycle
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.activeViewController viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.activeViewController viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.activeViewController viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.activeViewController viewDidDisappear:animated];
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
for (UIViewController * viewController in self.segmentedViewControllers) {
[viewController didReceiveMemoryWarning];
}
}
- (void)viewDidUnload {
self.segmentedControl = nil;
self.segmentedViewControllers = nil;
self.activeViewController = nil;
//[self.segmentedControl release];
[super viewDidUnload];
}
#end
I am doing some exercises with delegate, but now I have a problem with a UIView. This is my storyboard
I want to change the color of the UIView with 3 UISliders. The range of UISliders is from 0 to 255.
And this is my code:
ColorField is the UIView custom class
ColorField.h
#import <UIKit/UIKit.h>
#protocol ColorFieldDelegate <NSObject>
-(NSArray *)giveMeColors;
#end
#interface ColorField : UIView
#property (nonatomic , weak) IBOutlet id<ColorFieldDelegate> delegate;
#end
ColorField.m
#import "ColorField.h"
#implementation ColorField
#synthesize delegate = _delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
NSArray *arrayOfColors = [self.delegate giveMeColors];
int red = [[arrayOfColors objectAtIndex:0] intValue];
int green = [[arrayOfColors objectAtIndex:1] intValue];
int blue = [[arrayOfColors objectAtIndex:2] intValue];
NSLog(#"Red --> %d" ,red);
NSLog(#"Green --> %d" ,green);
NSLog(#"Blue --> %d \n\n" ,blue);
self.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
}
#end
ColorViewController.h
#import <UIKit/UIKit.h>
#import "ColorField.h"
#interface ColorViewController : UIViewController <ColorFieldDelegate>
#property (nonatomic) IBOutlet ColorField *colorField;
#property (weak, nonatomic) IBOutlet UISlider *redSlider;
#property (weak, nonatomic) IBOutlet UISlider *greenSlider;
#property (weak, nonatomic) IBOutlet UISlider *blueSlider;
#end
ColorViewController.m
#import "ColorViewController.h"
#interface ColorViewController ()
#property (nonatomic) double redQuantity;
#property (nonatomic) double greenQuantity;
#property (nonatomic) double blueQuantity;
#end
#implementation ColorViewController
#synthesize colorField = _colorField;
#synthesize redSlider;
#synthesize greenSlider;
#synthesize blueSlider;
#synthesize redQuantity;
#synthesize blueQuantity;
#synthesize greenQuantity;
- (void)viewDidLoad
{
[super viewDidLoad];
[self.colorField setDelegate:self];
[self.colorField setNeedsDisplay];
self.redQuantity = 125.0;
self.blueQuantity = 125.0;
self.greenQuantity = 125.0;
[self.colorField setNeedsDisplay];
// Do any additional setup after loading the view, typically from a nib.
}
-(ColorField *)colorField
{
if (_colorField == nil) {
_colorField = [[ColorField alloc] init];
}
return _colorField;
}
- (void)viewDidUnload
{
[self setColorField:nil];
[self setRedSlider:nil];
[self setGreenSlider:nil];
[self setBlueSlider:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
-(IBAction)changeRedQuantity:(UISlider *)sender
{
//methods of UISliders
self.redQuantity = [sender value];
[self.colorField setNeedsDisplay];
}
-(IBAction)changeBlueQuantity:(UISlider *)sender
{
self.blueQuantity = [sender value];
[self.colorField setNeedsDisplay];
}
-(IBAction)changeGreenQuantity:(UISlider *)sender
{
self.greenQuantity = [sender value];
[self.colorField setNeedsDisplay];
}
-(NSArray *)giveMeColors
{
NSNumber *redNumber = [NSNumber numberWithDouble:self.redQuantity];
NSNumber *greenNumber = [NSNumber numberWithDouble:self.greenQuantity];
NSNumber *blueNumber = [NSNumber numberWithDouble:self.blueQuantity];
NSArray *array = [[NSArray alloc] initWithObjects:redNumber, greenNumber,blueNumber, nil];
return array;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#end
BUT...this is the result: It show me only RED, GREEN and BLUE colors without gradation, for example: RGB (255,0,75) is THIS
and not THIS:
I don't know with it can't show me gradation...
Thanks!!
Marco Manzoni
You have to divide your slidervalues by 255.0.
[UIColor colorWithRed:red/255.0 green:green/255.0 blue:blue/255.0 alpha:1.0];
colorWithRed only accepts values 0.0-1.0
I am another rookie in iPhone programming and I have a very basic question which I can not answer.
First of all, I am writing code in xcode 3.1.4, so that I can learn the basics on an old platform and hopefully in the near future this will allow me to create portable apps (in the sense that I will be supporting iPhone 3 as well). Unfortunately though, from what I understand, apple has stripped the documentation that came with xcode 3.1.4 and this makes it hard to guess what is the right way of doing things, since the current documentation and examples suggest routes more relevant to iOS 5 (e.g. storyboard). So, even though I appear to understand the whole concept of MVC, and although my first real toy app is actually functioning it is certainly not managing the memory correctly as the relevant dealloc methods are not used (the relevant NSLogs that I have are not shown). For the learning process I am following the course material that is online from CS193P in Winter of 2010.
To the specifics now.
I want to create a single-window app (Polygon, Assignment 3). Let's forget about the interface builder; all views/subviews will be created programmatically. For that I create a custom UIViewController. I also create a custom UIView in order to describe a custom subview of my single view that I want to present. (It is very likely that we disagree with my approach here already but for now I seriously believe that what I am trying here is conceptually right). In the app delegate (.h) I declare my mainController and this is all I really declare. The file is the following:
#import <UIKit/UIKit.h>
#import "MainViewController.h"
#interface MySimpleHelloPolyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MainViewController * mainController;
}
#property (nonatomic, retain) IBOutlet UIWindow * window;
#property (nonatomic, assign) IBOutlet MainViewController * mainController;
#end
On runtime, I want mainController to allocate the necessary memory for the main view presented to the user and also add a subview of my custom UIView (this will be the canvas for drawing polygons). So, essentially I want to treat window as a container, the view of mainController to actually present the main view to the user, and to that view I will also have attached a subview with an instance of our custom canvas (custom view). Below is the AppDelegate.m file:
#import "MySimpleHelloPolyAppDelegate.h"
#implementation MySimpleHelloPolyAppDelegate
#synthesize window, mainController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window setBackgroundColor:[UIColor blueColor]]; // I do not want to see 'blue' on runtime
// On the creation of the MainViewController subclass I indicated that I want a nib for my new controller
// simply because this is the recommended way by apple. Apparently this should be an overkill for a simple
// one-window app, but nevertheless it should be ok.
mainController = [[MainViewController alloc] initWithNibName:nil bundle:nil];
[window addSubview:mainController.view];
[window makeKeyAndVisible];
}
- (void)dealloc {
NSLog(#"(AppDelegate): Dealloc is called");
[mainController.view removeFromSuperview];
[mainController release];
[window release];
[super dealloc];
}
#end
Let's see the MainViewController.h:
#import <UIKit/UIKit.h>
#import "Polygon.h"
#import "Canvas.h"
#interface MainViewController : UIViewController {
IBOutlet UILabel * numSidesTextLabel;
IBOutlet UILabel * numSidesValueLabel;
IBOutlet UILabel * advancedOptionsLabel;
IBOutlet UILabel * polygonNameLabel;
IBOutlet UISwitch * advancedOptionsSwitch; // Not supported yet
IBOutlet UIButton * increaseButton;
IBOutlet UIButton * decreaseButton;
IBOutlet Canvas * myCanvas;
Polygon * myPolygon;
}
#property (nonatomic, retain) IBOutlet UILabel * numSidesTextLabel;
#property (nonatomic, retain) IBOutlet UILabel * numSidesValueLabel;
#property (nonatomic, retain) IBOutlet UIButton * increaseButton;
#property (nonatomic, retain) IBOutlet UIButton * decreaseButton;
#property (nonatomic, retain) IBOutlet UIView * myCanvas;
#property (nonatomic, retain) IBOutlet Polygon * myPolygon;
- (IBAction) increase;
- (IBAction) decrease;
- (void) updateInterface;
#end
Now let's see the MainViewController.m:
#import "MainViewController.h"
#implementation MainViewController
#synthesize numSidesTextLabel, numSidesValueLabel, decreaseButton, increaseButton, myCanvas, myPolygon;
- (IBAction) decrease {
[myPolygon setNumberOfSides:([myPolygon numberOfSides]-1)];
[self updateInterface];
}
- (IBAction) increase {
[myPolygon setNumberOfSides:([myPolygon numberOfSides]+1)];
[self updateInterface];
}
- (void) updateInterface {
int sides = [myPolygon numberOfSides];
UIColor * myOceanColor = [UIColor colorWithRed:0.00 green:0.333 blue:0.557 alpha:1.00];
[increaseButton setTitleColor:myOceanColor forState:UIControlStateNormal];
[increaseButton setTitleColor:[UIColor darkGrayColor] forState:UIControlStateDisabled];
[decreaseButton setTitleColor:myOceanColor forState:UIControlStateNormal];
[decreaseButton setTitleColor:[UIColor darkGrayColor] forState:UIControlStateDisabled];
numSidesValueLabel.text = [NSString stringWithFormat:#"%d", sides];
decreaseButton.enabled = YES; increaseButton.enabled = YES;
if (sides == MAX_NUM_SIDES_CONSTANT) increaseButton.enabled = NO;
else if (sides == MIN_NUM_SIDES_CONSTANT) decreaseButton.enabled = NO;
[myCanvas updateState:sides withName:[myPolygon name]];
[myCanvas setNeedsDisplay];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
- (void)loadView {
self.view = [[UIView alloc] initWithFrame:CGRectMake(0.0, 20.0, 320.0, 460.0)];
self.view.backgroundColor = [UIColor whiteColor];
}
- (void)viewDidLoad {
CGRect tempFrame;
UIColor * oceanColor = [UIColor colorWithRed:0.000 green:0.333 blue:0.557 alpha:1.000];
// Draw the labels
tempFrame = CGRectMake(20.0, 20.0, 150.0, 20.0);
numSidesTextLabel = [[UILabel alloc] initWithFrame:tempFrame];
numSidesTextLabel.text = #"Number of sides:";
numSidesTextLabel.textAlignment = UITextAlignmentLeft;
[self.view addSubview:numSidesTextLabel];
[numSidesTextLabel release];
tempFrame = CGRectMake(160.0, 20.0, 40.0, 20.0);
numSidesValueLabel = [[UILabel alloc] initWithFrame:tempFrame];
numSidesValueLabel.text = #"-----";
numSidesValueLabel.textAlignment = UITextAlignmentLeft;
[self.view addSubview:numSidesValueLabel];
[numSidesValueLabel release];
tempFrame = CGRectMake(20.0, 125.0, 160.0, 20.0);
advancedOptionsLabel = [[UILabel alloc] initWithFrame:tempFrame];
advancedOptionsLabel.text = #"Advanced options";
advancedOptionsLabel.textAlignment = UITextAlignmentLeft;
[self.view addSubview:advancedOptionsLabel];
[advancedOptionsLabel release];
// Draw the advanced switch
tempFrame = CGRectMake(205.0, 120.0, 120.0, 60.0);
advancedOptionsSwitch = [[UISwitch alloc] initWithFrame:tempFrame];
[advancedOptionsSwitch setOn:NO animated:YES];
[self.view addSubview:advancedOptionsSwitch];
[advancedOptionsSwitch release];
// Decrease Button
decreaseButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // autoreleased
[decreaseButton setTitle:#"Decrease" forState:UIControlStateNormal];
[decreaseButton setTitleColor:oceanColor forState:UIControlStateNormal];
[decreaseButton setTitleColor:[UIColor darkGrayColor] forState:UIControlStateDisabled];
decreaseButton.frame = CGRectMake(20.0, 60.0, 110.0, 40.0);
[decreaseButton addTarget:self action:#selector(decrease) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:decreaseButton];
// Increase Button
increaseButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // autoreleased
[increaseButton setTitle:#"Increase" forState:UIControlStateNormal];
[increaseButton setTitleColor:oceanColor forState:UIControlStateNormal];
[increaseButton setTitleColor:[UIColor darkGrayColor] forState:UIControlStateDisabled];
increaseButton.frame = CGRectMake(190.0, 60.0, 110.0, 40.0);
[increaseButton addTarget:self action:#selector(increase) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:increaseButton];
// Initialize the polygon
myPolygon = [[Polygon alloc] init];
numSidesValueLabel.text = [NSString stringWithFormat:#"%d", [myPolygon numberOfSides]];
// Prepare the canvas
CGRect myCanvasFrame = CGRectMake(20.0, 160.0, 280.0, 280.0);
myCanvas = [[Canvas alloc] initWithFrame:myCanvasFrame withNumSides:[myPolygon numberOfSides] withPolygonName:[myPolygon name]];
[self.view addSubview:myCanvas];
[myCanvas release];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
numSidesTextLabel = nil;
numSidesValueLabel = nil;
advancedOptionsLabel = nil;
myPolygon = nil;
myCanvas = nil;
[self.view release]; self.view = nil;
}
- (void)dealloc {
NSLog(#"(MainViewController): Dealloc is called");
[numSidesTextLabel removeFromSuperview];
[numSidesValueLabel removeFromSuperview];
[advancedOptionsLabel removeFromSuperview];
[myPolygon release];
[myCanvas removeFromSuperview]; // This should generate additional output
[super dealloc];
}
#end
Now let's have a look on the Canvas.h file:
#import <UIKit/UIKit.h>
#import "PrepDefs.h"
#interface Canvas : UIView {
IBOutlet UILabel * polygonNameLabel;
int currentStateNumSides;
CGPoint center;
}
#property (nonatomic, retain) UILabel * polygonNameLabel;
#property (nonatomic, assign) int currentStateNumSides;
#property (nonatomic, assign) CGPoint center;
+ (NSArray *) pointsForPolygonInRect:(CGRect) rect numberOfSides:(int) numberOfSides;
- (id) initWithFrame:(CGRect)frame withNumSides:(int)sides withPolygonName:(NSString *) name;
- (void) updateState:(int)sides withName:(NSString *)name;
#end
The Canvas.m file:
#import "Canvas.h"
#implementation Canvas
#synthesize polygonNameLabel, currentStateNumSides, center;
+ (NSArray *) pointsForPolygonInRect:(CGRect)rect numberOfSides:(int)numberOfSides {
CGPoint center = CGPointMake(rect.size.width / 2.0, rect.size.height / 2.0);
float radius = 0.9 * center.x;
NSMutableArray *result = [NSMutableArray array];
float angle = (2.0 * M_PI) / numberOfSides;
float exteriorAngle = M_PI - angle;
float rotationDelta = angle - (0.5 * exteriorAngle);
for (int currentAngle = 0; currentAngle < numberOfSides; currentAngle++) {
float newAngle = (angle * currentAngle) - rotationDelta;
float curX = cos(newAngle) * radius;
float curY = sin(newAngle) * radius;
[result addObject:[NSValue valueWithCGPoint:CGPointMake(center.x + curX, center.y + curY)]];
}
return result;
}
- (id) initWithFrame:(CGRect)frame withNumSides:(int)sides withPolygonName:(NSString *)name {
if (self = [super initWithFrame:frame]) {
// Initialization code
[self setBackgroundColor:[UIColor brownColor]];
currentStateNumSides = sides;
center = CGPointMake ([self bounds].size.width / 2.0, [self bounds].size.height / 2.0);
polygonNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, center.y - 10.0, [self bounds].size.width, 20.0)];
polygonNameLabel.text = name;
polygonNameLabel.textAlignment = UITextAlignmentCenter;
polygonNameLabel.backgroundColor = [UIColor clearColor];
[self addSubview:polygonNameLabel];
[polygonNameLabel release];
}
return self;
}
- (id)initWithFrame:(CGRect)frame {
NSLog(#"(Canvas, -initWithFrame): You should always use initWithFrame:withNumSides:withPolygonName:");
return [self initWithFrame:frame withNumSides:DEFAULT_NUM_SIDES withPolygonName:DEFAULT_POLYGON_NAME];
}
- (void)drawRect:(CGRect)rect {
// Drawing code
NSArray * points = [Canvas pointsForPolygonInRect:[self bounds] numberOfSides:[self currentStateNumSides]];
CGContextRef currentContext = UIGraphicsGetCurrentContext();
[[UIColor blackColor] set];
UIRectFrame ([self bounds]);
CGContextBeginPath (currentContext);
for (int i = 0; i < [points count]; i++) {
CGPoint currentPoint;
NSValue * currentValue;
currentValue = [points objectAtIndex:i];
currentPoint = [currentValue CGPointValue];
//NSLog(#"(%.1f, %.1f)", currentPoint.x, currentPoint.y);
if (i == 0)
CGContextMoveToPoint(currentContext, currentPoint.x, currentPoint.y);
else
CGContextAddLineToPoint(currentContext, currentPoint.x, currentPoint.y);
}
CGContextClosePath(currentContext);
[[UIColor yellowColor] setFill];
[[UIColor blackColor] setStroke];
CGContextDrawPath(currentContext, kCGPathFillStroke);
}
- (void) updateState:(int)sides withName:(NSString *)name {
currentStateNumSides = sides;
polygonNameLabel.text = name;
}
- (void)dealloc {
NSLog(#"(Canvas): Calling dealloc");
[polygonNameLabel removeFromSuperview]; polygonNameLabel = nil;
[super dealloc];
}
#end
The PrepDefs.h file:
#ifndef __PREP_DEFS_H__
#define __PREP_DEFS_H__
#define MIN_NUM_SIDES_CONSTANT 3
#define DEFAULT_NUM_SIDES 5
#define MAX_NUM_SIDES_CONSTANT 12
#define DEFAULT_POLYGON_NAME #"Pentagon"
#endif
Finally the files for the Polygon class. The Polygon.h file:
#import <Foundation/Foundation.h>
#import "PrepDefs.h"
#interface Polygon : NSObject {
int numberOfSides;
int minimumNumberOfSides;
int maximumNumberOfSides;
}
#property int numberOfSides;
#property int minimumNumberOfSides;
#property int maximumNumberOfSides;
#property (readonly) float angleInDegrees;
#property (readonly) float angleInRadians;
#property (readonly) NSString * name;
- (void) setNumberOfSides:(int)numSides;
- (void) setMinimumNumberOfSides:(int)minNumSides;
- (void) setMaximumNumberOfSides:(int)maxNumSides;
- (id) initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max;
#end
The Polygon.m file:
#import "Polygon.h"
#implementation Polygon
#synthesize numberOfSides, minimumNumberOfSides, maximumNumberOfSides, angleInDegrees, angleInRadians, name;
- (void) setNumberOfSides:(int)numSides {
if ((numSides >= [self minimumNumberOfSides]) && (numSides <= [self maximumNumberOfSides])) numberOfSides = numSides;
else NSLog(#"PolygonShape [setNumberOfSides]: Assignment out of bounds");
}
- (void) setMinimumNumberOfSides:(int)minNumSides {
if (minNumSides >= MIN_NUM_SIDES_CONSTANT) minimumNumberOfSides = minNumSides;
else NSLog(#"PolygonShape [setMinimumNumberOfSides]: Assignment out of bounds");
}
- (void) setMaximumNumberOfSides:(int)maxNumSides {
if (maxNumSides <= MAX_NUM_SIDES_CONSTANT) maximumNumberOfSides = maxNumSides;
else NSLog(#"PolygonShape [setMaximumNumberOfSides]: Assignment out of bounds");
}
- (float) angleInDegrees {
int sides = [self numberOfSides];
return ((float) (180.0 * ((double) (sides - 2)) / ((double) sides)));
}
- (float) angleInRadians {
int sides = [self numberOfSides];
return ((double) M_PI) * ((double) (sides - 2.0)) / ((double) sides);
}
- (NSString *) name {
NSString * s;
switch ([self numberOfSides]) {
case 3: s = [NSString stringWithString:#"Triangle"]; break;
case 4: s = [NSString stringWithString:#"Square"]; break;
case 5: s = [NSString stringWithString:#"Pentagon"]; break;
case 6: s = [NSString stringWithString:#"Hexagon"]; break;
case 7: s = [NSString stringWithString:#"Heptagon"]; break;
case 8: s = [NSString stringWithString:#"Octagon"]; break;
case 9: s = [NSString stringWithString:#"Enneagon"]; break;
case 10: s = [NSString stringWithString:#"Decagon"]; break;
case 11: s = [NSString stringWithString:#"Hendecagon"]; break;
case 12: s = [NSString stringWithString:#"Dodecagon"]; break;
default: NSLog(#"PolygonShape [name]: I should never enter here."); s = nil; break;
}
return s;
}
- (id) init {
return [self initWithNumberOfSides:DEFAULT_NUM_SIDES minimumNumberOfSides:MIN_NUM_SIDES_CONSTANT maximumNumberOfSides:MAX_NUM_SIDES_CONSTANT];
}
- (id) initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max {
if (self = [super init]) {
// Cautiously initialize everything to zero
numberOfSides = 0;
minimumNumberOfSides = 0;
maximumNumberOfSides = 0;
// Attempt the actual assignment
[self setMaximumNumberOfSides:max];
[self setMinimumNumberOfSides:min];
[self setNumberOfSides:sides];
}
return self;
}
- (NSString *) description {
return [NSString stringWithFormat:#"Hello I am a %d-sided polygon (aka a %#) with angles of %.3f degrees (%.6f radians)", [self numberOfSides], [self name], [self angleInDegrees], [self angleInRadians]];
}
- (void) dealloc {
NSLog(#"(Polygon): Dealloc is called");
[super dealloc];
}
#end
After all the above, I believe the questions are:
Why dealloc functions are not used? Where do I actually have leaks?
When I initialize my mainController, should I pass as parameter the name of the nib file that was created when I created the custom class for the mainController?
Should I initialize the mainController and its view differently?
Should I use awakeFromNib instead of loadView or viewDidLoad?
Other comments that you have regarding the entire approach? Such as good or bad programming practices for one-screen applications? It really is a small program, so, I believe this is not an open-ended question. If however you think that this is an open-ended question, feel free not to answer. This is probably a naive question by a rookie to some veterans.
I really appreciate all the time that you spend on this and I am looking forward to your feedback.
If I run Build and Analyze this loads without errors according to the Analyzer but the app crashes. If I remove the [myStates release]; analyzer complains about possible leak but the nib loads and runs just fine. MyStateList is a nib which has a pickerview inside that loads a plist if this helps. Please help.
Main TrialViewControllerViewController Implementation File
#import "TrialViewControllerViewController.h"
#import "MyStateList.h"
#implementation TrialViewControllerViewController
- (void)viewDidLoad {
[super viewDidLoad];
MyStateList *myStates = [[MyStateList alloc] initWithNibName:#"MyStateList" bundle:nil];
[self.view addSubview:[myStates view]];
//[myStates release];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
}
- (void)dealloc {
[super dealloc];
}
#end
Here is what i am trying to load
MyStateList.h
#import <UIKit/UIKit.h>
#interface MyStateList : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource> {
UIPickerView *pickerView;
NSMutableArray *statesArray; // Written array
NSDictionary *stateListDictionary,*stateListDictionaries;
NSArray *firstDisplayArray,*updateDisplayArray,*switchDisplayArray;
NSInteger dTag;
NSString *nott,*verify,*notes;
IBOutlet UILabel *labelOne,*labelTwo,*labelThree,*labelName;
}
#property (nonatomic, retain) UIPickerView *pickerView;
#property (nonatomic, retain) NSDictionary *stateListDictionary,*stateListDictionaries;
#property (nonatomic, retain) NSArray *firstDisplayArray,*updateDisplayArray,*switchDisplayArray;
#property (nonatomic, retain) IBOutlet UILabel *labelOne,*labelTwo,*labelThree,*labelName;
#property (nonatomic, retain) NSString *nott,*verify,*notes;
- (void)loadData;
- (void)placeData;
- (void)createPicker;
#end
MyStateList.m
#import "MyStateList.h"
#implementation MyStateList
#synthesize pickerView;
#synthesize stateListDictionary,stateListDictionaries,firstDisplayArray,updateDisplayArray,switchDisplayArray ;
#synthesize labelOne,labelTwo,labelThree,labelName;
#synthesize nott,verify,notes;
- (void)viewDidLoad
{
[super viewDidLoad];
[self createPicker];
}
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [statesArray count];
}
-(UIView *)pickerView:(UIPickerView *)pickerViewCust viewForRow:(NSInteger)row forComponent: (NSInteger)component reusingView:(UIView *)view
{
NSString *rowItem = [statesArray objectAtIndex: row];
UILabel *lblRow = [[[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, [pickerViewCust bounds].size.width, 44.0f)]autorelease];
[lblRow setTextAlignment:UITextAlignmentCenter];
[lblRow setTextColor: [UIColor blueColor]];
[lblRow setText:rowItem];
[lblRow setBackgroundColor:[UIColor clearColor]];
return lblRow;
}
- (void)createPicker
{
NSString *path = [[NSBundle mainBundle] pathForResource:
#"StateArray" ofType:#"plist"];
stateListDictionary = [NSDictionary dictionaryWithContentsOfFile:path];
labelName.text = [NSString stringWithFormat:#"Arizona"];
[self loadData];
float screenWidth = [UIScreen mainScreen].bounds.size.width;
float pickerWidth = screenWidth * 1 / 2;
float xPoint = screenWidth / 2 - pickerWidth / 1;
pickerView = [[UIPickerView alloc] init];
[pickerView setDataSource: self];
[pickerView setDelegate: self];
[pickerView setFrame: CGRectMake(xPoint, 280.0f, pickerWidth, 180.0f)];
pickerView.showsSelectionIndicator = YES;
[pickerView selectRow:2 inComponent:0 animated:YES];
[self.view addSubview: pickerView];
}
- (void)loadData
{
firstDisplayArray = [stateListDictionary objectForKey:#"Arizona"];
dTag = 1;
[self placeData];
stateListDictionary = nil; // kill the list
statesArray = [[NSMutableArray alloc] init];
[statesArray addObject:#"Alabama"];
[statesArray addObject:#"Alaska"];
[statesArray addObject:#"Arizona"];
[statesArray addObject:#"Arkansas"];
[statesArray addObject:#"California"];
}
- (void)placeData
{
if (dTag == 1)
{
switchDisplayArray = firstDisplayArray;
dTag = 0;
} else {
switchDisplayArray = updateDisplayArray;
}
nott = [switchDisplayArray objectAtIndex:0];
verify = [switchDisplayArray objectAtIndex:1];
notes = [switchDisplayArray objectAtIndex:2];
labelOne.text = nott;
labelTwo.text = verify;
labelThree.text = notes;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent: (NSInteger)component
{
NSString *path = [[NSBundle mainBundle] pathForResource:
#"StateArray" ofType:#"plist"];
stateListDictionaries = [NSDictionary dictionaryWithContentsOfFile:path];
labelName.text = [statesArray objectAtIndex: row];
updateDisplayArray = [stateListDictionaries objectForKey:labelName.text];
[self placeData];
}
- (void)dealloc
{
[pickerView release];
[stateListDictionary release];
[stateListDictionaries release];
[statesArray release];
[super dealloc];
}
#end
If I had to guess, MyStatesList is a subclass of UIViewController.
If you release myStates at the end of the block, you're essentially removing the brain from your view controller, but leaving its body there. You need to keep the controller itself around as well as the view, as the view is owned by the controller. Not the other way around.
The view from your view controller is retained by the view, but you killed the view controller itself. The bigger problem is you CAN'T just add views from UIViewControllers in this manner. On iOS5 you have the ability to use addChildViewController: and prior to that you can use one of the provided container controllers.
You do indeed need to release your MyStateList object.
Here's what's happening:
You initialize a new MyStateList, which has a retain count of 1
You add a subview to your view, and that subview is NOT the MyStateList object, but the ivar view of your MyStateList object.
When you don't release your myStates object, you are indeed leaking this object, since nothing has a reference to this object anymore, and the memory was never deallocated. (Its retain count never reached 0.)
That having been said, what kind of error occurs when your application crashes? I'm guessing that MyStateList is a UIViewController, and the view is then attempting to access/communicate with its parent, which has been released/deallocated.
In your -(void)dealloc; you are calling [super dealloc] first, this is wrong. Make it the last call in the method. This should fix your crash.
- (void)dealloc
{
// Wrong Way
[super dealloc];
[pickerView release];
[stateListDictionary release];
[stateListDictionaries release];
[statesArray release];
}
`
- (void)dealloc
{
// Right way
[pickerView release];
[stateListDictionary release];
[stateListDictionaries release];
[statesArray release];
[super dealloc];
}
you add the view [myStates view], to the controller's view, so the view is hold by the controller's view.
then you release "myStates" for avoid memeory leak, it is removed.
and I guess in your view [myStates view], there must be some delegates related to the object "myState", but it was removed just before. So, the app crash.
To avoid both problems, memory leak and crash. I think you should make the "myStates" hold by your controller as a member variable. And you could release "myState" when your viewUnloaded.
Well, i have 2 view controllers the fist has three buttons each one represents an image on an array of images. When a user presses a button moves on the second view controller which has just an IBOutlet UIImageView to view the image. How can i do this programming trick using the UIImagePickerController? here are my files:
// PhotoListViewController.h
#import <UIKit/UIKit.h>
#import "PhotoDetailViewController.h"
#interface PhotoListViewController : UIViewController {
IBOutlet UIButton *button;
IBOutlet UIImageView *image1;
IBOutlet UIImageView *image2;
IBOutlet UIImageView *image3;
IBOutlet UILabel *label1;
IBOutlet UILabel *label2;
IBOutlet UILabel *label3;
IBOutlet UILabel *nameMikro1;
IBOutlet UILabel *nameMikro2;
IBOutlet UILabel *nameMikro3;
NSString *nameMikroProp;
IBOutlet PhotoDetailViewController *photoDetailViewController;
}
#property (nonatomic, retain) PhotoDetailViewController *photoDetailViewController;
-(IBAction)showImage:(id)sender;
#property (copy) NSString *nameMikroProp;
#end
// PhotoListViewController.m
#import "PhotoListViewController.h"
#import "PhotoDetailViewController.h"
#implementation PhotoListViewController
#synthesize nameMikroProp;
#synthesize photoDetailViewController;
-(IBAction)showImage:(id)sender{
photoDetailViewController = [[PhotoDetailViewController alloc]init];
//photoDetailViewController.delegate = self;
if([sender tag] == 4){
//[photoDetailViewController.imageViewprop setImage:[UIImage imageNamed:#"zaab.png"]];
//[self presentModalViewController:self.imgPicker animated:YES];
}
else if([sender tag] == 5){
}
else{
}
[self.navigationController pushViewController:photoDetailViewController animated:YES];
[photoDetailViewController release];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
NSMutableArray *imageArray = [[NSMutableArray alloc] init];
[imageArray addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"main" ofType:#"jpg"]]];
[imageArray addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"main2" ofType:#"jpg"]]];
[imageArray addObject:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"main3" ofType:#"jpg"]]];
NSMutableArray *nameArray = [[NSMutableArray alloc] init];
[nameArray addObject:#"zaab's photo one"];
[nameArray addObject:#"zaab's photo two"];
[nameArray addObject:#"zaab's photo three"];
nameMikro1.text = nameMikroProp;
nameMikro2.text = nameMikroProp;
nameMikro3.text = nameMikroProp;
if([#"zaab" isEqualToString:nameMikro1.text]) {
[image1 setImage:[imageArray objectAtIndex:0]];
[image2 setImage:[imageArray objectAtIndex:1]];
[image3 setImage:[imageArray objectAtIndex:2]];
[label1 setText:[nameArray objectAtIndex:0]];
[label2 setText:[nameArray objectAtIndex:1]];
[label3 setText:[nameArray objectAtIndex:2]];
}
else if([#"evza" isEqualToString:nameMikro1.text]) {
[image1 setImage:[UIImage imageNamed:#"evza.jpg"]];
}
[imageArray release];
[nameArray release];
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[nameMikro1 release];
[nameMikro2 release];
[nameMikro3 release];
[label1 release];
[label2 release];
[label3 release];
[image1 release];
[image2 release];
[image3 release];
[super dealloc];
}
#end
// PhotoDetailViewController.h
#import <UIKit/UIKit.h>
#interface PhotoDetailViewController : UIViewController<UINavigationControllerDelegate, UIImagePickerControllerDelegate> {
IBOutlet UIImageView *imageViewprop;
UIImagePickerController *imgPicker;
}
#property (nonatomic, retain) UIImageView *imageViewprop;
#property (nonatomic, retain) UIImagePickerController *imgPicker;
- (IBAction)grabImage;
#end
// PhotoDetailViewController.m
#import "PhotoDetailViewController.h"
#implementation PhotoDetailViewController
#synthesize imageViewprop;
#synthesize imgPicker;
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
imageViewprop.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"main" ofType:#"jpg"]];
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
}
- (IBAction)grabImage {
[self presentModalViewController:self.imgPicker animated:YES];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
self.imgPicker = [[UIImagePickerController alloc] init];
self.imgPicker.allowsImageEditing = NO;
self.imgPicker.delegate = self;
self.imgPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
Why do you need an image picker controller to show an image? ImagePickerController is used to pick an image from the album or by using camera.
What you can do is to pass the image from the PhotoListViewController to PhotoDetailViewController.
In the PhotoDetailViewController, you can have a property of UIImage (synthesized), so that you can set it before loading it. Then in the PhotoDetailVC use a UIImageView to show the image.
If you are looking for more advance functionality with image, look at the three20 framework at
three20 at github.