i have the following code
#interface TestYourInfoViewController : UIViewController {
IBOutlet UIImageView * questionImage;
NSArray *historyQuestions;
int questionHistoryNo;
}
#property(nonatomic,retain) UIImageView * questionImage;
#property(nonatomic,retain) NSArray *historyQuestions;
#property int questionHistoryNo;
-(IBAction)solution:(id)sender;
#end
- (void)viewDidLoad
{
NSArray* array = [[NSArray alloc]init];
historyQuestions = array;
historyQuestions=UmRandomOrder(49, 1, 0);
questionImage.image = [UIImage imageNamed:[NSString stringWithFormat:#"h%#.jpg",[self.historyQuestions objectAtIndex:0]]];
[array release];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
-(IBAction)solution:(id)sender{
questionHistoryNo= questionHistoryNo+1;
questionImage.image = [UIImage imageNamed:[NSString stringWithFormat:#"h%#.jpg",[self.historyQuestions objectAtIndex:questionHistoryNo]]];
}
when i press the action button it gives me exception in the line [self.historyQuestions objectAtIndex:questionHistoryNo]
i believe the problem is in the nsarray somehow but i don't know what is it.. the exception is
can anyone help me ..
Actually DarkDust has it correct: the source code for UMRandomOrder shows that it properly returns an autorelease NSMutableArray. So, just change the first three lines of your viewDidLoad from:
NSArray* array = [[NSArray alloc]init];
historyQuestions = array;
historyQuestions=UmRandomOrder(49, 1, 0);
to just:
self.historyQuestions=UmRandomOrder(49, 1, 0);
And you'll be fine.
To be specific, there's no need to alloc/init/assign an array you're about to write over, and by using the property setter (self.historyQuestions = ), you'll automatically do a proper retain, as well as avoiding a potential memory leak. That also explains why it works in viewDidLoad (the autoreleased UmRandomOrder is still valid), but not in the action button (it has since been released).
Related
I have a property of
#property (nonatomic, strong) NSMutableArray *timesArray;
It is used to populate the data in my UITableView. When I want to clear my view, I do this:
- (void)clearView {
self.nameField.text = #"";
self.noteField.text = #"";
if ([_timesArray count] > 0) {
[self.timesArray removeAllObjects];
[self.customTableView reloadData];
}
}
The removeAllObjects causes a crash. I am not sure why. I looked around and a lot of posts talk about an object being overreleased. How is that happening if I'm using ARC and not calling retain/release on any objects. My _timesArray just holds NSDate objects I get from a UIDatePicker.
My stack trace looks like:
My insertPill looks like:
- (void)insertPill:(id)sender {
//[[NSNotificationCenter defaultCenter] postNotificationName:InsertPillNotification object:self];
[self clearView];
}
If I don't removeAllObjects, and just do:
NSMutableArray *emptyArray = [[NSMutableArray alloc] initWithCapacity:0];
self.timesArray = emptyArray;
This works. But I'd still like to know why by removing the objects it does not work.
Edit: I initialize the array in viewDidLoad:
_timesArray = [[NSMutableArray alloc] initWithCapacity:0];
When I want to add a new object to the array, I do this:
NSMutableArray *tempUnsortedArray = [[NSMutableArray alloc] initWithArray:_timesArray];
[tempUnsortedArray addObject:_datePicker.date];
self.timesArray = tempUnsortedArray;
I'm not sure if the way I'm adding data the array is causing the issue or not.
You're getting a doesNotRecognizeSelector: exception. This probably means that the object you think is a NSMutableArray is not really one. It is probably an NSArray. Where are you assigning the object?
To start debugging the issue, po the object before calling removeAllObjects. What type of object is it reported as?
Otherwise it could be possible that there is a non NSObject element in timesArray.
#property (nonatomic, strong) NSMutableArray *timesArray;
if ([_timesArray count] > 0)
It seems, you syntesize your property like this:
#syntesize timesArray = _timesArray;
You chacking count of _timesArray, but removing object from timesArray. I never set new name for my properties and don't sure how it works, but I dont like it.
I have various UILabels that I would like to hide using a for-loop.
#interface MyViewController : UIViewController {
NSMutableArray * labelArray;
}
#property (nonatomic, retain) IBOutlet UILabel *label1, *label2, *label3;
...
-(void)viewDidLoad {
[super viewDidLoad];
[labelArray initWithObjects:label1,label2,label3,nil];
for(int i=0; i<sizeof(labelArray); i++){
UILabel *label = [labelArray objectAtIndex:i];
label.hidden = !label.hidden;
}
}
When this is executed, the labels are not hidden. They have been "hooked up" in Interface Builder. What am I doing incorrectly? Thanks!
That is not what sizeof is for. That's a compiler construct that tells you how many bytes a value takes up, which has no clue how many elements are in an NSMutableArray at runtime. You want:
for (UILabel *label in labelArray) {
label.hidden = !label.hidden;
}
If that doesn't work, then your array does not contain the objects you believe it does — quite possibly, you've forgotten to actually create the array — simply sending init to nil does not create an object. Either way, you should probably be doing labelArray = [[NSMutableArray alloc] initWithObjects:label1,label2,label3,nil];. alloc and init go together hand-in-glove.
So I have been searching around the internet fo methods to randomly select then display an image. And so far I have this in my .m viewcontroller:
#import "classgenViewController.h"
#implementation classgenViewController
#synthesize images, randomStrings;
- (void)viewDidLoad {
[super viewDidLoad];
self.randomStrings = [NSArray arrayWithObjects:#"Frag.png",
#"Semtex.png",
#"Tomahawk.png",
nil];
}
- (IBAction)showRandomString {
UIImageView *images = [randomStrings objectAtIndex: (arc4random() % [randomStrings count])];
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
self.images = nil;
}
- (void)dealloc {
[self.images release];
[self.randomStrings release];
[super dealloc];
}
#end
but the *images says it is an unused variable. How can I use it. It is declared in my .h, I have used the (property, nonatomic) method on it, as well as synthesized it. Help?
You're just assigning images variable and not actually doing anything with it. Also - you're creating instance of UIImageView class while assigning an actual string to it. Do you have UIImageView outlet assigned to your UIViewController? If so - just assign an UIImage to it like this:
- (IBAction)showRandomString {
NSString *randomImageFilename = [randomStrings objectAtIndex: (arc4random() % [randomStrings count])];
UIImage *image = [UIImage imageNamed:randomImageFilename];
uiImageViewOutlet.image = image;
}
First you declared it as a property. Then you overrode that by declaring it as a local variable in showRandomStrings. That local variable is never used. To assign the value to the instance variable declared in the .h file, remove the "UIImageView *" before it.
Also, you seem to want to assign an NSString to UIImageView pointer. That will only end in tears.
Maybe you want to do something like this:
UIImage* newImage = [UIImage imageNamed:<your random string here>];
images.image = newImage;
Where "images" is presumably a UIImageView* that you set up in .h and which you configured in the Interface Builder.
For me as a beginner, I would use a method that is not professional at all, but it works :)
First of all in the interface builder add the imageViews you want along with the images.
and make them hidden.
Then add an array with objects referring to the images you have, than use
randomImage = [nameOfArray objectAtIndex:arc4random() % [nameOfArray count]];
then add some if statements along with a single line to make the imageView appear, for example:
if ([randomImage isEqual:#"image1"]) {
image1.hidden = NO;
}
I tried that method before, and it worked.
Good luck
I have three images that I want to cycle through when clicking on a UIButton.
How would I go about doing this?
This is what I have so far, but it's not really working.
//the images
NSString* imageNames[] = {"MyFirstImage", "AnotherImage", whatever else};
int currentImageIndex = 0;
and
- (IBAction)change{
UIImage* imageToShow = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource: imageNames[currentImageIndex] ofType:#"png"];
if( currentImageIndex++ == sizeof(imageNames)/sizeof(NSString)) //check to see if you hit the last image
{
currentImageIndex = 0; //start over
}
}
Ideas?
Any help will be greatly appreciated! Thanks!
Steven's suggestion to subclass UIButton is a good one. Once you get a some more experience with Objective C, you should consider his approach, but I can tell by the code you've posted that you're new to Objective C, so you may need to learn to use the basic Foundation classes first.
One reason your code isn't working is because you're trying to pass C string literals to pathForResource:, which requires an NSString object. NSStrings are objects in Objective C, not character pointers as they are in C. You can construct an NSString object using the literal syntax, #"quotes-with-an-at-in-front".
Here is code that implements the algorithm you attempted to write, using Objective C Foundation classes rather than C data types:
// YourController.h
#interface YourController : UIViewController {
NSArray *imageNames;
NSInteger currentImageIndex;
UIButton *yourButton;
}
#property (nonatomic, retain) NSArray *imageNames;
#property (nonatomic, retain) IBOutlet UIButton *yourButton; // Presumably connected in IB
- (IBAction)change;
#end
// YourController.m
#import "YourController.h"
#implementation YourController
#synthesize imageNames, yourButton;
- (void)dealloc {
self.imageNames = nil;
self.yourButton = nil;
[super dealloc];
}
- (void)viewDidLoad {
self.imageNames = [NSArray arrayWithObjects:#"MyFirstImage", #"AnotherImage", nil];
currentImageIndex = 0;
[super viewDidLoad];
}
- (IBAction)change {
UIImage* imageToShow = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[imageNames objectAtIndex:currentImageIndex] ofType:#"png"];
currentImageIndex++;
if (currentImageIndex >= imageNames.count) {
currentImageIndex = 0;
}
[yourButton setImage:imageToShow forState:UIControlStateNormal];
}
#end
You will want to subclass UIButton and add a new property that maintains state. You will also want to have three properties to maintain the images of the three new states. Then in your "drawRect:" method, swap out the standard buttons images based on your state and then call the [super drawRect:] method.
I'm writing an iPhone app. I have a header file that looks like this:
#interface EditTagsViewController : UITableViewController {
NSMutableArray *allTags;
NSMutableArray *selectedTags;
NSInteger currentFavorite;
}
#property (nonatomic, retain) NSMutableArray *allTags;
#property (nonatomic, retain) NSMutableArray *selectedTags;
#property (nonatomic) NSInteger currentFavorite;
#end
In the implementation file, my viewDidLoad method looks like this:
- (void)viewDidLoad {
NSMutableArray *aTags = [[NSMutableArray alloc] initWithArray:[Tag findAllTags]];
self.allTags = aTags;
[aTags release];
NSMutableArray *sTags = [[NSMutableArray alloc] initWithArray:[Tag findByFavoriteId:currentFavorite]];
self.selectedTags = sTags;
[sTags release];
UIBarButtonItem *add = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(addNewTag:)];
self.navigationItem.rightBarButtonItem = add;
[add release];
[super viewDidLoad];
}
Here is my dealloc method:
- (void)dealloc {
[allTags release];
[selectedTags release];
[super dealloc];
}
What's confusing to me is that when I run the app both in the simulator and on the device itself, using Instruments (memory leaks), it tells me that this line in my viewDidLoad method is leaking an array:
self.selectedTags = sTags;
It's confusing because I'm using the exact same technique with 2 different variables, and yet no leak is reported with the first one.
I feel like I'm missing something obvious here. Any ideas?
Your code looks correct to me. Is it possible that one of [Tag findAllTags] or [Tag findByFavoriteId:] is leaking? Are you making sure to set self.allTags and self.selectedTags to nil in dealloc?
Be mindful of the difference between saying self.allTags = ... and allTags = .... Because allTags is a property and has the retain attribute, whenever you assign via self.allTags = ..., it implicitly calls the setter method [self setAllTags:...], which invokes retain on the new value and release on the old value (if any). You're doing it correctly in this code sample, but if elsewhere you're assigning straight to allTags (without the self.), you're not releaseing the old value, which may be the source of the leak. Likewise for selectedTags.
Have a look at findByFavoriteId is there a retain there? That is the only difference I can see between the aTags and sTags are used in your example