How do I name a file differently everytime I allocate it? - iphone

The Code:
// Inside my BoardsViewController.m
- (void)createImage {
imageCounter ++;
board = [[Boards alloc] init];
[self.view addSubview:board];
[board release];
board is supposed to be changed everytime, and is instead of being named board: be named 1_board, 2_board, 3_board, everytime I call this method
}
I want to have the Boards(UIView subclass) have the name of imageCounter, and also have board. Kinda like: 1_board. Meaning I want to have a Boards called something different everytime I call this method.
EDIT:
This should help maybe:
I want to have this one method that I will call multiple times allocate a Board(subclass of UIView) but have them all different names other than only one name. Meaning I increment the view counter everytime before allocating the view. So I want to have the name include the variable inside the integer: viewCounter. So that I cal call the different views seperatly and control each allocation differently.

It is not clear what do you want to achieve. If you want to distinguish between different Board instances later you can use a tag property (available in all UIView subclasses):
- (void)createImage {
imageCounter ++;
Boards *board = [[UIImageView alloc] init];
board.tag = imageCounter;
[self.view addSubview:board];
[board release]; // Note that you need this line also, you current code produces memory leak
}
Later you can get each of the created Boards using:
Boards* yourBoard = [self.view viewWithTag: someTag];
You can also define some custom identifier in your Board class if you want. Changing the name of the local variable (e.g. board to whatever_board) does not really make sense as this name will not be accessible outside of the scope of this function anyway.

Related

using string variable from one class in another

Rookie question: I am writing a program that will generate a specific string and then display it in a text window in a different view controller. I have been testing to ensure that the code in fact generates the string using NSLog commands and I know the code is working as intended. For some reason it is not transferring across the view controller and I cant figure out why. Any help? Here is a snippet of the code:
CreateStoryViewController.m
- (IBAction)makeStory:(id)sender
{
StoryLine *myStory =[[StoryLine alloc] init];
[myStory setStory];
self.story = myStory.plot;
NSLog(#"story is %#", self.story);//this is generating the correct story string
self.displayStoryController = [[BIDDisplayStoryViewController alloc] initWithNibName:#"DisplayStoryView" bundle:nil];
[self.view insertSubview:self.displayStoryController.view atIndex:1];
}
DisplayStoryViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
BIDCreateStoryViewController *newStory = [[BIDCreateStoryViewController alloc] init];
NSLog(#"newStory.story is %#",newStory.story);//this generates null message
self.storyDisplay.text = newStory.story;
}
This is wrong. You're instantiating a new BIDCreateViewController object inside your second view controller. This is not the same as the original BIDCreateViewController object that pushed your second BIDDisplayStoryViewController.
You need to declare a string property in your BIDDisplayStoryViewController's header file.
Something like
#property (nonatomic, retain /*or strong, if using ARC*/) NSString *storyToDisplay;
Be sure to synthesize this in your implementation file as well.
When you create BIDDisplayStoryViewController inside your first view controller, you need to do it as follows:
self.displayStoryController = [[BIDDisplayStoryViewController alloc] initWithNibName:#"DisplayStoryView" bundle:nil];
self.displayStoryViewController.storyToDisplay = self.story;
Now inside your second view controller you can access this using self.myStory.
While this will solve your problem (and please do understand that it's not my intention to be rude here), I feel that there's a lack of understanding of how iOS (and OOP in general) works.
In your viewDidLoad method you are making a whole new story. This story is totally different from the one you made in the makeStory: method. You should add a StoryLine Property to DisplayStoryViewController.h, and set that after you init your displayStoryController.
make the intended variable a property type at .h file, so the other file can access it

Select multiple images

I have this UITableView which is displaying images, downloaded rom a database, as a matrix: 4 images in each table row.
To be able to select images from the views I'm using a UITapGestureRecognizer. To make each selection unique I've been trying to tag each tap recognizer and each imageView. That's where the problem is...
I've put a log within the for-loop that is creating and tagging the imageViews and recognizers and I can see in the output that they pass through all the values. However when I try to get the tag by later pressing an image I always get "3" (the last number in the table row). This makes me think the tags are simlpy overwriting eachother even though I'm creating a new object in each loop. Either that or I'm reading it out the wrong way.
Unrelated parts cut out.
for (NSInteger i = 0; i < 4; i++){
asyncImage = [[AsyncImageView alloc]
initWithFrame:frame];
[asyncImage loadImageFromURL:url];
asyncImage.tag = i;
NSLog(#"TAG %d", asyncImage.tag);
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap)];
tapRecognizer.view.tag = i;
NSLog(#"TapTAG %d", asyncImage.tag);
[asyncImage addGestureRecognizer:tapRecognizer];
}
And the method:
- (void)handleTap{
NSLog(#"TAP %d", self.tapRecognizer.view.tag);
}
If you think I'm doing it all totally wrong, a light push in the right direction is always welcome!
Thanks in advance, Tom
The following line has no effect until the gesture recognizer has been added to a view:
tapRecognizer.view.tag = i;
This is because tapRecognizer's view is initially nil. Make the assignment on the last line of your for loop to correct this problem.
Also your NSLog is always showing the tag of the last recognizer that you have added
self.tapRecognizer.view.tag // Instance variable
not the one that fired the event. Change handleTap as follows:
- (void)handleTap:(UITapGestureRecognizer*) tapRecognizer{
NSLog(#"TAP %d", tapRecognizer.view.tag);
}
You should also replace the tapRecognizer instance variable with a local variable in the method that adds the recognizer to the view, and add a colon : to your selector name:
action:#selector(handleTap:)
// HERE: ----^
I think you're doing it wrong in the loop.
Your loop is run 4 times and every time you run the loop you store AsyncImageView to the asyncImage variable (local or instance?). So the first time you run the loop, you create an object and store it at the asyncImage location, the second time this is overwritten, the third....
You have initialized 4 ImageViews, but you are only referencing to the last one. And the last one holds the correct GestureRecognizer, you want.
When do you add the ImageView to a view?
If you use the instance varable and overwrite it directly, all the other ImageViews you added to the screen point to the pointer of asyncImage. And the pointer - after running 4 times the loop and exchanging asyncImage data - points to the last image in the loop.
Hope you understand, what the problem is here.

Recycling labels in for loop and releasing them

What's the correct way of creating an UILabel and releasing it again when I want to re-use this until i'm out of records in my array?
I wanted to this this:
// create label
UILabel *labelIWishToRecycle;
for (int i = 0; i < [myArrayFullOfItems count]; i++) {
// Edit the label
labelIWishToRecycle = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 640)];
}
// Release label
[labelIWishToRecycle release];
When I do it this way I get a crash for releasing it. So I just don't release it. Works like a charm now. Of course, this is not the way, so I was wondering what IS.
Should I create and release the label for every item in the array? Or should I create it outside the for-loop but release it within? Or ...?
Thanks in advance.
For what are you using the label!? If you are adding it to a view, than you have to use a new instance everytime.. if you only do size calculations or stuff like that, than you could use the same label over and over again.
But the trick is to initialize your local variable:
UILabel *labelIWishToRecycle = nil;
If you have done this, it is save to send release on it (also if no real label has been assigned yet). Before, your pointer is pointing on a random address and you are trying to release the object at that address. That will be a crash in the most cases.
(Guessing the problem case is the one, when your array count is zero.)

How can I see the intermediate updates on my UI while debugging iPad code?

I am developing an app in which I am using a plist file. There are 21 key-value pairs in the plist. Each pair is a dictionary (type) with 6 items. The dictionary contains a set of images. In my program, I am using the path to retrieve the images. My requirement is that the images should be displayed one-by-one on the imageView. i have done it successfully. The images are being dispalyed exactly from plist.
So my question is can I use the debugger to see the intermediate execution of the plist? When I placed breakpoints in my code, and run using the debugger, I am able to step into the code and the images are displayed on the view only after the whole execution of plist with 21 key-value pairs is done. How can I see the images on the view while debugging each pair?
(void)setSequenceInfo:(NSDictionary *)sequenceInfo
{
[self.subviews makeObjectsPerformSelector:#selector(removeFromSuperview)];
self.sequenceQueue = [NSMutableArray array];
//load the sequenceinfo dictionary
[_sequenceInfo release];
if (!sequenceInfo)
return;
_sequenceInfo = [sequenceInfo retain];
//create one UIImageView by sequence
NSMutableDictionary* views = [NSMutableDictionary dictionaryWithCapacity:[sequenceInfo count]];
for (NSString* identifier in _sequenceInfo)
{
UIImageView* seqView = [[UIImageView alloc] initWithFrame:self.bounds];
seqView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
seqView.contentMode = self.contentMode;
//the image is hidden until its sequence is played
seqView.hidden=YES;
//add the newly created image view to our subviews
[self addSubview:seqView];
//also store it in our sequenceViews dictionary
[views setValue:seqView forKey:identifier];
[seqView release];
}
self.sequenceViews = views;
}
In order to "see" intermediate results while using the debugger, you'll have to change the structure of your code to return to the main run loop, so that the UIImageView has the chance to run and display the new image. You could set up a timer that fires periodically, and in the timer routine you change the UIImageView's image to the next one in the sequence. Then you set your breakpoint in the timer handler method in gdb, and when you hit that breakpoint each time you should see the previously displayed image.
EDIT: here's some more detail, based on what I think you want to do. Realize, though, that I think there's no "magic wand" to be able to see changes on the screen while you're in the debugger. You have to return to the Run Loop so that your UIKIt widgets get cycles to draw themselves.
For example, say you have this method:
- (void) updateTwoLabels:(NSString *)newText
{
self.label1.text = newText;
self.label2.text = newText; // put breakpoint on this line
}
and you want to stop in the debugger just before label2's text is set, and see that label1 has changed. Well, I think there's no way of doing that, except by modifying your code, and calling yourself again with performSelector:withObject:afterDelay: so that the main run loop can run for a while then call your code again:
BOOL callAgain = NO;
BOOL setLabel2 = YES;
- (void) updateTwoLabels:(NSString *)newText
{
self.label1.text = newText;
if ( setLabel2 )
self.label2.text = newText; // put breakpoint on this line
if ( callAgain )
[self performSelector:#selector(updateTwoLabels:) withObject:newText afterDelay:0];
}
in this way, when you're debugging, you can set callAgain to YES and setLabel2 to NO in gdbg, and keep "continuing" until you see that label1 has changed. That's the basic technique.
Do the whole method in a background thread but call GUI stuff on the main thread. For example: [self performSelectorOnMainThread:#selector(addSubview:) withObject:seqView waitUntilDone:YES]. Don't forget to make an autorelease pool at the beginning of the method (the one that runs in the background thread) and drain it at the end of it.

initializing UIView subclass with parameters in iphone sdk?

Iam a newbiew to iPhone development. Version of my SDK is 2.2
In my code, UIViewController is used to change view dynamically once the app is launched, a method in the UIViewController is called to know which view should be initialized along with parameters, which goes to a 'switch-case' and assign a view to current view according to the parameter, like this:
case 1:
currentView = [[View01 alloc] init];
break;
case 2:
currentView = [[View02 alloc] init];
break;
and outside the switch-case:
[self.view addSubview:currentView.view];
I wonder f can pass a parameter along with initialization, like iniWithNibName or so? I need this because have to manipulate in the leaded view, according to the view from which its called.
Thanks.
One way to approach this is to modify your View01 and View02 classes to include an initWithParam: initialiser.
i.e. add
- (id) initWithParam:(NSString *)myParam;
to the #interface section and add
- (id) initWithParam:(NSString *)myParam {
if (self = [self init]) {
// handle or store 'myParam' somewhere for use later
}
return self;
}
to the #implementation section. Notice how the initWithParam: message internally calls the existing init. Obviously you could change the type, or number of parameters passed in as required.
Another approach would be to provide a property on your view class, so you could do something like the following:
currentView = [[View01 alloc] init];
currentView.myParam = #"SomeValue";
Which approach works the best will depend somewhat on your particular application needs.