How Can I get Xcode to randomize a picture? - iphone

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

Related

Problem With NSArray

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

ABTableViewCell and adding an image

For a view in my iPhone application, I am using a subclass of the ABTableViewCell (https://github.com/enormego/ABTableViewCell). It's a fairly simple cell, but I wanted to use this for the scrolling speed I need, because a lot of them can in the table at once.
Here is the header of the file:
#interface WHUserTableViewCell : ABTableViewCell {
NSString* Name;
NSString* DetailsText;
UIImage* UserImage;
}
#property (nonatomic, copy) NSString* Name;
#property (nonatomic, copy) NSString* DetailsText;
#property (nonatomic, copy) UIImage* UserImage;
I know that by using 'copy' on an image, I am only supporting iOS 4.2 and up, but that is something I might fix later.
I follow the way AteBits uses this cell, by creating custom set methods for the properties, like this:
- (void) setUserImage:(UIImage *) userImage
{
[UserImage release];
UserImage = [userImage copy];
[self setNeedsDisplay];
}
- (void) setName:(NSString *) name
{
[Name release];
Name = [name copy];
[self setNeedsDisplay];
}
- (void) setDetailsText:(NSString *) detailsText
{
[DetailsText release];
DetailsText = [detailsText copy];
[self setNeedsDisplay];
}
The images that are assigned to the 'UserImage' property, are coming from a Singleton class, which provides caching and downloading of the images. So that class should be the 'owner' of the images.
There is only one problem, once the cell deallocs, and I release all the properties the application crashes on the [UserImage release] line, here's my dealloc method:
- (void)dealloc
{
[super dealloc];
[UserImage release];
[Name release];
[DetailsText release];
}
This cell uses custom drawing, just like AteBits explains in his famous blog post about this. What is the correct and fastest way to handle images for this. I would like to continue using my singleton caching/downloading class to handle images, but I don't think that is the source of the problem, since I am copying the image objects.
[super dealloc]; should be the last line of - (void)dealloc.
Related: Why do I have to call super -dealloc last, and not first?

where do I instantiate my class so I can access it throughout my app?

I've been working through some objective-c/ iOS dev books and I've hit a stumbling block. I get the feeling that I'm missing something dumb here, so I'm sure you guys can help, because you're all so damn smart :-).
I've got a very simple app that consists of 1 button and 1 label. Pushing the button puts a message in the label. I've created a class that includes a method to create said message. Here is the problem:
#import "classTestViewController.h"
#implementation classTestViewController
#synthesize myLabel;
- (void)viewDidLoad
{
}
-(IBAction) pressGo:(id)sender{
MyClass * classTester = [[MyClass alloc] init];
classTester.count = 15;
NSString *newText = [classTester makeString ];
myLabel.text = newText;
}
- (void)dealloc
{
[classTester release];
[myLabel release];
[super dealloc];
}
The output of this app, in my label, is "Yay 15". So you can see the problem, the only way I can get this to work is to instantiate the class right there, in the "pressGo" method. This isn't desirable because another method can't access or change the class variable count. Also I get a warning that local declaration of classTester hides instance variable. If I move the class instantiation to the viewDidLoad method, which seems right, the other methods can't access it anymore.
#import "classTestViewController.h"
#implementation classTestViewController
#synthesize myLabel;
- (void)viewDidLoad
{
MyClass * classTester = [[MyClass alloc] init];
}
-(IBAction) pressGo:(id)sender{
classTester.count = 15;
NSString *newText = [classTester makeString ];
myLabel.text = newText;
}
- (void)dealloc
{
[classTester release];
[myLabel release];
[super dealloc];
}
The output of that is nada. If I try to access just one variable, classTester.count, for example, even after setting it, I get a 0 value. I also get the override warning here as well.
So my question is, how can i get access to that class instance throughout my app and not just in one method? I'm using a view based application.
Declare classTester in your interface file with:
#class MyClass
#interface classTestViewController : UIViewController
{
MyClass *classTester;
}
// Any other custom stuff here
#end
Then instantiate it in your viewDidLoad method with:
classTester = [[MyClass alloc] init];
And you should be able to access the ivar from any method within this class. If you want it to be accessible to your entire app, #Waqas link will point you in the right direction.
You need to create a singleton class which instantiate once and is available inside whole project
Have a look
http://projectcocoa.com/2009/10/26/objective-c-singleton-class-template/

Multiple custom backgrounds for UIToolbar

In order to create an absolute bottomed footer on top of a tableView I found that using UIToolbar for this and adding custom views for it worked fine.
My problem is that I already use this as a toolbar for a webview, and here with another background image than I need now.
By replacing the drawRect function in UIToolbar+addition.m I have a global toolbar for this that works fine in my webviews.
How can I expand this so that I can select which version(background) to use the different places?
My UIToolbar+addition.m:
#import "UINavigationBar+addition.h"
#implementation UIToolbar (Addition)
- (void) drawRect:(CGRect)rect {
UIImage *barImage = [UIImage imageNamed:#"toolbar-bg.png"];
[barImage drawInRect:rect];
}
#end
Try creating separate .h and .m files for each "version", and import the appropriate .h into the class file you'd like it to affect.
Why not just add a barImage property to your extension?
#interface UIToolbar (Addition)
#property (nonatomic, retain) UIImage *barImage;
#end
Then, in your implementation (I'm doing this assuming you're not using ARC. If you are, obviously remove the retain/release stuff):
#implementation UIToolbar (Addition)
#synthesize barImage = _barImage;
//Override barImage setter to force redraw if property set after already added to superView...
- (void)setBarImage:(UIImage *)barImage {
if (_barImage != barImage) {
UIImage *oldBarImage = [_barImage retain];
_barImage = [barImage retain];
[oldBarImage release];
//Let this UIToolbar instance know it needs to be redrawn in case you set/change the barImage property after already added to a superView...
[self setNeedsDisplay];
}
}
- (void) drawRect:(CGRect)rect {
[self.barImage drawInRect:rect];
}
//If you're not using ARC...
- (void)dealloc {
[barImage release];
[super dealloc];
}
#end
Now, all you have to do is set the barImage property after instantiating your UIToobar. e.g.:
UIToolBar *myToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; //Or whatever frame you want...
myToolbar.barImage = [UIImage imageNamed:#"toolbar-bg.png"];
[self.view addSubView:myToolbar];
[myToolbar release];
And, if you want to change it after it's already onscreen, you can do so by just setting the barImage property to a new UIImage.
Looks like it's been a year since this question was posted, but hopefully this might help someone.

Data is not persisting in multiple instances of the same object (iOS)

I'm having issues with data persisting inside of multiple instances of objects I'm creating.
I have a class "IconViewController" that extends UIViewController that I pass information to, such as the name of the image it should be using:
//IconViewController.h
#interface AppIconViewController : UIViewController
{
NSString *imageName;
}
#property (nonatomic, retain) NSString *imageName;
- (void) doSomething;
//IconViewController.m
#implementation AppIconViewController
#synthesize imageName;
NSNumber *iconWidth;
- (void)loadView
{
[super loadView];
UIImageView *iconImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
iconWidth = [NSNumber numberWithFloat:iconImage.bounds.size.width];
[iconImage release];
NSLog(#"iconWidth: %f", [iconWidth floatValue]);
}
- (void) doSomething
{
NSLog(#"iconWidth: %f", [iconWidth floatValue]);
}
In another view controller, I'm instantiating several instances of these IconViewControllers and passing different sized images to them:
AppIconViewController *appIcon1 = [[AppIconViewController alloc] initWithNibName:nil bundle:nil];
appIcon1.imageName = #"Image65PXWide.png";
[self.view addSubview:appIcon1.view];
AppIconViewController *appIcon2 = [[AppIconViewController alloc] initWithNibName:nil bundle:nil];
appIcon2.imageName = #"Image105PXWide.png";
[self.view addSubview:appIcon2.view];
Okay, the weirdness is that when I'm creating these, I'm getting logs back that are accurate...appIcon1 logs "iconWidth: 65.0" and appIcon2 logs "iconWidth: 105.0". But when I call:
[appIcon1 doSomething];
...my log is "iconWidth:105.0".
Why is the data in the first instance reflecting the data in the second instance? What am I missing?
EDIT:
I know that if I declare iconWidth in the header and synthesize it as a property, that it will work. So what I'm wondering is how to make a private version of it persist. Because I tried retaining the NSNumber with:
iconWidth = [[NSNumber numberWithFloat:iconImage.bounds.size.width] retain];
...and it still doesn't work. Does it have to be synthesized and public?
EDIT #2:
Okay, so I figured out that once I declare iconWidth in my header, it works just fine, and I don't have to synthesize it so it keeps it private. Not sure why exactly it won't work if declared in the implementation file - does anyone have any insight into why and if there's any purpose in declaring variables at the top of an implementation but not in the header? Just curious now more than anything.
Synthesizing doesn't make anything private. It just generates getter/setter methods according to declared properties.
By placing iconWidth in the implementation, outside of any methods, it's essentially a class-level variable. So it gets overwritten by the last thing that writes to it. You already have imageName declared in the interface, so why not just put iconWidth there as well (instance variables are private by default)?
In your method doSomething, you are assuming iconWidth is set up properly.
However, iconWidth is created as an autorelease object in loadView method, so when loadView finishes, the main loop will release iconWidth and you are getting random values.
To fix this you have to retain iconWidth so you can use it in other methods
iconWidth = [[NSNumber numberWithFloat:iconImage.bounds.size.width] retain];
As a general rule, method that doesn't start with init will return autorelease object, so you have to be careful how you instantiate an object and whether you need to call retain on it.