I have initialized an NSMutableArray like so:
tileArray = [[NSMutableArray alloc]initWithObjects:
(tile1,tile2,tile3,tile4,tile5,tile6,tile7,tile8,tileBlank), nil];
I'm attempting to print out the size of the array by doing:
NSLog(#"Size2: %i", [tileArray count]);
It tells me that the size is 0. What would be causing this?
The .h file
#interface STView : UIView{
NSMutableArray *tileArray;
TileView *tile1;
TileView *tile2;
TileView *tile3;
TileView *tile4;
TileView *tile5;
TileView *tile6;
TileView *tile7;
TileView *tile8;
TileView *tileBlank;
int width;
int height;
}
- (void) getScreenSize;
#end
TileView.m
- (id)initWithFrame:(CGRect)frame withImageNamed: (NSString*) imageName{
if (self = [super initWithFrame:frame]) {
//initilization code
image = [[UIImageView alloc]
initWithImage: [UIImage imageNamed: imageName]];
image.frame = self.bounds;
image.opaque = YES;
[self addSubview:image];
} return self;
}
First, remove the parentheses. The value of the expression (tile1,tile2,tile3,tile4,tile5,tile6,tile7,tile8,tileBlank) is tileBlank.
Second, where are these tile* guys getting declared? Are they all reliably non-null?
You need to define the array as a property in your .h and synthesize it then use self.titleArray. Whatever function you declared the array in (e.g. viewDidLoad), it's only storing the info in that function. In every other function it's nil, that's why you need the retained property.
Related
Today I'm facing a new problem:
I have a ViewController (Subclass of NSView) and another class (Subclass of NSObject) which, through an IBAction, try to call back the viewController to redraw its view using SetNeedsDisplay:YES.
The method to redraw the view (ViewController.m) is:
- (void) redrawView {
[self setNeedsDisplay:YES]
}
// With an NSLog i see that the method is called !
// Instead of self i tried even an outlet connected to the custom view.
}
What I'm doing to call the ViewController method through my other class is:
1) #import "ViewController.h"
2) into the IBAction i made a new istance of ViewController as:
ViewController *newIstanceOfViewController = [[ViewController alloc] init]
3) [newIstanceOfViewController redrawView]
The log show me that setNeedsDisplay is called but drawrect no ! Why ? I have forgotten to init or subview something ? Thanks
THE ORIGINAL CODE HERE (DIFFERENT NAME OF METHODS DUE TO LANGUAGE, SAME SYNTAX)
// Controller.h
#import <Cocoa/Cocoa.h>
#interface Controller : NSView {
IBOutlet NSView *tastierinoView;
}
- (void) aggiornaTastierinoView;
#end
// Controller.m
#import "Controller.h"
#implementation Controller
//Contatore numero volte disegno view
int contatore = 0;
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
tastierinoView = [[NSView alloc] init];
}
return self;
}
- (void) aggiornaTastierinoView { //THIS IS THE METHOD TO CALL REDRAW
[tastierinoView setNeedsDisplay:YES];
NSLog(#"Chiamo setneedsDisplay\n\n");
}
- (void)drawRect:(NSRect)dirtyRect
{
contatore++;
NSLog(#"La view รจ stata disegnata %d volte\n\n",contatore);
[super drawRect:dirtyRect];
// Drawing code here.
NSBezierPath* percorso = [NSBezierPath bezierPath];
[[NSColor cyanColor] set];
[percorso moveToPoint:NSMakePoint(150, 150)];
[percorso lineToPoint:NSMakePoint(250, 150)];
[percorso setLineWidth:5.0];
[percorso stroke];
}
#end
// ManipolatorePin.h
#import <Foundation/Foundation.h>
#interface ManipolatorePin : NSObject {
IBOutlet NSWindow *finestraPrincipaleWindow;
IBOutlet NSTextField *codiceTextField;
NSArray *coordinate_x;
NSArray *coordinate_y;
//L'array sotto riportato serve, tramite un ciclo for, a salvare il codice pin spezzato in singoli numeri che corrisponderanno al punto.
NSMutableArray *numeroAllaIndexArray;
}
- (IBAction)aggiornaTastierino:(id)sender;
#end
// ManipolatorePin.m
#import "ManipolatorePin.h"
#import "Controller.h"
#implementation ManipolatorePin
- (void)awakeFromNib {
coordinate_x = [[NSArray alloc] initWithObjects:#"150",#"50",#"150",#"250",#"50",#"150",#"250",#"50",#"150",#"250", nil];
coordinate_y = [[NSArray alloc] initWithObjects:#"50",#"150",#"150",#"150",#"250",#"250",#"250",#"350",#"350",#"350", nil];
numeroAllaIndexArray = [[NSMutableArray alloc] init];
NSLog(#"Array coordinate iniziallizato.\nTest:(%#) -> deve risultare \"50\"\n\n",[coordinate_x objectAtIndex:4]);
}
- (IBAction)aggiornaTastierino:(id)sender {
NSString *codiceString = [[NSString alloc] initWithFormat:[NSString stringWithFormat:#"%#",[codiceTextField stringValue]]];
NSLog(#"codiceTextField = %#", codiceString);
int lunghezzaCodiceString;
NSLog(#"Il codice risulta essere composto da (%d) numeri\n\n",[codiceString length]);
//Svuoto array
[numeroAllaIndexArray removeAllObjects];
for (lunghezzaCodiceString = 0; lunghezzaCodiceString < [codiceString length]; lunghezzaCodiceString++) {
//Compilo array (Ci provo ahah)
NSString *carattereDelCodiceStringInEsame = [[NSString alloc] init];
carattereDelCodiceStringInEsame = [codiceString substringWithRange:NSMakeRange(lunghezzaCodiceString,1)];
NSLog(#"Aggiungo il numero (%#) all'array 'numeroAllaIndexArray'",carattereDelCodiceStringInEsame);
[numeroAllaIndexArray addObject:carattereDelCodiceStringInEsame];
}
//DEBUG - DA QUI IN POI E' CANCELLABILE
NSLog(#"\n\nCiclo for termitato\nProcesso concluso con successo\n\n\nContenuto array:");
int conteggioArray;
for (conteggioArray = 0; conteggioArray < [numeroAllaIndexArray count] ; conteggioArray++ ) {
NSLog(#"index (%d) -> (%#)",conteggioArray,[numeroAllaIndexArray objectAtIndex:conteggioArray]);
NSLog(#"\n\n");
}
//FINE DEBUG
///////////////HERE THE INSTANCE TO CALL THE CONTROLLER
Controller *istanzaGestionaleController = [[Controller alloc] init];
[istanzaGestionaleController aggiornaTastierinoView];
}
#end
It sounds like you have two unrelated instances of ViewController. You need to call redrawView on the instance that actually has a view on the screen.
In your class (which is not the NSViewController), create a property like this:
#property (nonatomic, readwrite, weak) NSViewController *vc;
When the class is instantiated:
YourClass *yourInstance = [[YourClass alloc] init];
assign the value of vc:
yourInstance.vc = self; // self is your NSViewController instance
Then when you want to trigger a redraw, you pass the command to self.vc inside your other class.
So I am trying to make a Circle class in Objective-C. I know Java and OOP, and a little bit of Objective-C, but I cannot figure out why my class will not initialize. Here is the Circle.h:
#import <Foundation/Foundation.h>
#import "Image.h"
#interface Circle : NSObject
{
Image *img;
CGPoint pos;
}
-(id) init;
-(void) draw;
#end
and here is the Circle.m file:
#import "Circle.h"
#implementation Circle
-(id) init{
self = [super init];
if (self != nil) {
img = [[Image alloc] initWithImage:[UIImage imageNamed:#"circle.png"]];
pos = CGPointMake((CGFloat)200, (CGFloat)200);
}
img = [[Image alloc] initWithImage:[UIImage imageNamed:#"circle.png"]];
pos = CGPointMake((CGFloat)200, (CGFloat)200);
return self;
}
-(void) draw{
[img renderAtPoint: pos centerOfImage: YES];
}
#end
Then in my main class I call:
//player is the name of the circle object (Circle *player;)
[player init];
And in my render method I call:
[player draw];
When I run my app, the image will not draw, any help?
You probably want to say:
player = [[Circle alloc] init];
Rather than just [player init], since the latter will do nothing if player is nil (the default value for members).
I am fairly new to Objective-C, this is the first time I really don't know what to do.
I have a class - Parser - which creates UIImageViews, inits them with images and adds them to the UIView. The class also adds these UIImageViews to NSMutableArray - imgArray, which is a property of another class - Page.
Then, on the click of a button, I call the Page class from a Manager class, loop through the imgArray and try to set a new images for the UIImageViews in the array.
It doesn't work. Actually nothing I do to the UIImageViews doesn't work.
I try [img removeFromSuperView], [img setHidden:YES] and more. It doesn't response.
Here I declare the Array property in Page:
#property (nonatomic, retain) NSMutableArray *imgArray;
Here is the code from Parser where I create the image and add it to the array:
UIImageView *img = [[UIImageView alloc] initWithFrame: frame];
NSString *name = [c imageSource];
[img setImage: [UIImage imageFromBook: name]];
[view addSubview: img];
[c setImage:img];
if (!page.imgArray)
{
page.imgArray = [[NSMutableArray alloc] init];
}
[page.imgArray addObject:img];
[img release];
Here is the loop code from the Manager:
- (void) set3D:(bool)is3D
{
Page *page = [[DataManager data] currentPage];
int count = [page.imgArray count];
for (int i = 0; i < count; i++)
{
UIImageView *img = [page.imgArray objectAtIndex:i];
[img setImage:[UIImage imageNamed:image3DSource]];
}
}
Thanks in advance for any help!
There is no need to store the UIImageView's in an array.
When the UIImageView's are created, you can tag them with an arbitrary number, like.
#define K_MIN_IMGV 100
#define K_MAX_IMGV 120
- (void) setupViews
{
for (NSInteger count = K_MIN_IMGV; count < K_MAX_IMGV; ++count)
{
UIImageView *imgV = // create image view, set properties
imgV.tag = count; // tag the views for easy retrieval later
...
[mainView addSubview: imgV]; // add subviews
[imgV release], imgV = nil; // mainView now manages, release our allocation
}
}
// how to set new images
- (void) setupNewImages
{
for (NSInteger count = K_MIN_IMGV; count < K_MAX_IMGV; ++count)
{
UIImageView *imgV = (UIImageView *) [mainView viewWithTag: count]; // retrieve imageView
[imgV setImage: newImage]; // set new image
}
}
// To remove the imageView, you can use
UIImageView *imgV = (UIImageView *) [mainView viewWithTag: 123];
[imgV removeFromSuperview];
Have you tried to enumerate through the array using:
for(UIImageView* imageView in page.imgArray)
{
//Do code
}
This will tell you if there any imageViews in page.imgArray.
How are you adding objects to NSMutableArray and how are you initialising your NSMutableArray.
I remember having a problem adding objects to NSMutableArray but setting my init to solved this:
NSMutableArray* mutableArray = [NSMutableArray array];
Also what properties have you set on imgArray in page? Are you retaining the values?
Need to see more code to gain a fuller understanding.
with this code, i want to add an image at the place the user taps. i want to add a new one for each tap.
-(void) foundDoubleTap:(UITapGestureRecognizer *) recognizer
{
UIView *piece = recognizer.view;
CGPoint locationInView = [recognizer locationInView:piece];
UIImageView *testPoint = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"inner-circle.png"]];
testPoint.frame = CGRectMake(0, 0, 20, 20);
testPoint.center = CGPointMake(locationInView.x, locationInView.y);
[self.imageView addSubview:testPoint];
NSMutableArray *tempTestPointArray = [[NSMutableArray alloc] initWithArray:testPointArray];
[tempTestPointArray addObject:testPoint];
testPointArray = tempTestPointArray;
NSLog(#"testPointArray: %#", testPointArray);
CGRect myRect = CGRectMake((testPoint.center.x + 12), (testPoint.center.y + 12), 10, 10);
UILabel *myLabel = [[UILabel alloc] initWithFrame:myRect];
myLabel.text = [NSString stringWithFormat:#"Point %d", [testPointArray count]];
myLabel.font = [UIFont fontWithName:#"Trebuchet MS" size:10];
[myLabel sizeToFit];
[imageView addSubview:myLabel];
[myLabel release];
[testPoint release];
//[tempTestPointArray release];
}
why is it that when i release tempTestPointArray, my code breaks when i implement a second tap? it crashes on:
NSMutableArray *tempTestPointArray = [[NSMutableArray alloc] initWithArray:testPointArray];
when i comment out the release for it, the Analyzer does not flag it as a leak. what happened to the rule, if you alloc/init it, you have to release it?
EDIT: adding .h file
.h file:
#interface TestPointMapViewController : UIViewController <UIScrollViewDelegate, UITextFieldDelegate>
{
//other code
NSArray *testPointArray;
}
//other code
#property (nonatomic, retain) NSArray *testPointArray;
//other code
#end
and then #synthesize testPointArray in .m file.
Your testPointArray is not assigning to a property, it is a plain ivar. Doing the line
testPointArray = tempTestPointArray;
Is leaking whatever is previously in testPointArray. Declare testPointArray as a retained property and change to.
self.testPointArray = tempTestPointArray;
Then keep the [tempTestPointArray release];
EDIT:
So the reason why this code is failing has to do with the magic of properties. The following code is equivalent.
self.testPointArray = tempTestPointArray;
[self setTestPointArray:tempTestPointArray];
When you do the #sythesize testPointArray; it is generating a setter method similar to this:
- (void)setTestPointArray:(NSMutableArray *)array {
id temp = testPointArray;
testPointArray = [array retain];
[temp release];
}
So when you don't use the property notation self.testPointArray you are not retaining the variable correctly. You are also losing a reference to a retained object, which is now a leak.
That make sense? If not please review this.
http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/objectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW1
I've got a problem at programming for iOS. Already looked for some similar problems but haven't found anything yet.
I'm creating at least 8 custom UIViews. As you can see in the appended code i'm running through a loop creating one instance per round. The reference of every object is on a different space in the memory but when i change a value in one object it only affects the object that has been created in the last loop-round (last created instance).
Any Ideas?
PadView.h:
#import <UIKit/UIKit.h>
#interface PadView : UIView {
}
- (void)setText:(NSString*)text;
#end
PadView.m:
#import "PadView.h"
#import "AVFoundation/AVFoundation.h";
#implementation PadView
AVAudioPlayer *player;
UILabel *label;
- (void)setText:(NSString*)text {
label.text = text;
}
- (void)initialize {
label = [[ UILabel alloc ] initWithFrame:CGRectMake(0.0, 93.0, 107.0, 13.0)];
label.backgroundColor = [UIColor clearColor];
label.font = [UIFont boldSystemFontOfSize:9];
label.textAlignment = UITextAlignmentCenter;
label.text = #"Empty";
[self addSubview:label];
[label release];
}
- (id) initWithCoder:(NSCoder *)aCoder {
if (self = [super initWithCoder:aCoder]) {
[self initialize];
}
return self;
}
- (id) initWithFrame:(CGRect)rect {
if (self = [super initWithFrame:rect]) {
[self initialize];
}
return self;
}
- (void)dealloc {
[super dealloc];
}
#end
Create the Objects:
NSMutableArray *pads = [[NSMutableArray alloc] initWithCapacity:8];
for (int i = 0; i < 8; i++) {
PadView *pad = [[PadView alloc] initWithFrame:CGRectMake(0.0, i*150, 107.0, 107.0)];
[padsView addSubview:pad];
[pads addObject:pad];
}
Call setText:
PadView *pad = [pads objectAtIndex:5];
[pad setText:#"test"];
Your variables:
AVAudioPlayer *player;
UILabel *label;
are defined in the #implementation block, so they are effectively global variables (in the C sense).
So basically, all your instances of PadView will change the same UILabel when you set its text property (which explains the behavior you are seeing).
I'm lacking some context, but it seems that you want label to be an instance variable instead (and I'd assume player as well). If that's the case, you need to declare them in the #interface block as follows:
#interface PadView : UIView {
AVAudioPlayer *player;
UILabel *label;
}
- (void)setText:(NSString*)text;
#end
pads is not initialized
NSMutableArray *pads = [[NSMutableArray alloc] initWithCapacity:8];
and you must release pad after adding as subview and to the array
By convention the class should be named PadView, not padView
edit
for(padView *pad in pads){
//manipulate each pad
}
//manipulate a certain pad
padView *pad = [pads objectAtIndex:5];
pad. //...