I have a custom class of type NSObject that contains a single NSMutableArray. This class is called Mutable2DArray and is designed to emulate a 2 dimensional array of type NSMutableArray. There is a custom init method - (id)initWithX:(int)x Y:(int)y that asks for the dimensions for the array and allocates the required arrays within the only array the class owns.
My issue is when I try to copy an instance of Mutable2DArray I get an error saying the copyWithZone is an unrecognized selector. I thought copy was a base method of NSObject so I'm confused why I cant create a copy of the instance like this:
Mutable2DArray *Array1 = [[Mutable2DArray alloc] initWithX:10 Y:10];
Mutable2DArray *Array2 = [Array1 copy];
Am I missing something so obvious here?
Things that I can think of to check, off the top of my head:
Does the header file actually declare the interface as inheriting from NSObject?
Does your custom initWithX: Y: method call [super init] before finishing?
Related
How can i lazily initialize a NSMutableArray of Buttons ? I do something like this :
-(NSMutableArray *)roasteryButtons
{
if(!roasteryButtons)
{
roasteryButtons = [ NSMutableArray new];
//other code
}
return roasteryButtons;
}
And don't know what to do to call this lazy initializer ? i.e. I need to initialize the array so that i may set the frame for every button in the array
What u have done is correct. Instead of allocating the array in the init method of class, u are allocating the array only when required. Thus it serves the purpose of lazily allocating.
In the class, Wherever you want the array, you just call,
NSMutableArray *arr = [self roasteryButtons];
Also declare the method in header file as, -(NSMutableArray*)roasteryButtons;.
If you want the reference of the array in other classes, the call like,
[classObj roasteryButtons];
I have shown it as instance method. You can also declare that as class method, if you want like that.
And release that in -(void)dealloc method.
I guess you know when to call this method, right ?
The first thing is that you shouldn't use "new" method, but [[NSMutableArray alloc] init] instead : You should have a look at all existing [Init] methods available for NSArray : there are a bunch of them (with capacity, with objects, etc...)
Anyway, you should add some parameters to your method [roasteryButtons] : parameters that will help the method to know, for instance how many buttons to create, what is the frame where they have to show, etc. So this will look a bit like
-(NSMutableArray *)roasteryButtonsWithFrame:(*Frame) andNumbersOfButtons:(int)
for example...
or instead of parameters, you can pass a reference to a delegate that will be able to give answers to those questions (How many buttons, what's my frame and bounds, etc.) So in this case, the method will look like :
-(NSMutableArray *)roasteryButtonsWithDelegate:(id)
(This delegate should implement a protocol that you will create, containing the different methods that the delegate will have to respond to. ie methods like [howManyButtons]...)
The Perfect Way to Lazy initialize is as follow
in .h file declare your NSMUtableArray as property as follow
#property (nonatomic,strong) NSMutableArray *array;
Now in .m file synthesize it and do lazy initialize in getter like as follow:
#synthesize array=_array;
(NSMutableArray *) array
{
(!_array) _array=[[NSMutableArray alloc]init];
//this line is called lazy intialization..this line will create MutableArray at program //run time.
return _array
}
Now answer why we need this is that it take care about that if no NSMutableArray is created then it create it at programme run time and like this your app will not crash.
You could make your method a class method:
+(NSMutableArray *)roasteryButtons {
in this way you will be able to call it like this:
[MyRoasteryButtonClass roasteryButtons];
and this will return you your object.
Hope this helps.
I do some iOS programming stuff and I have a UIViewController with a NSMutableArray:
#property (nonatomic, retain) NSMutableArray* mutableTestArray;
...
#synthesize mutableTestArray;
In viewDidLoad I want to call a method which is inside the implementation of this UIViewController:
//- (void)aTestMethod:(NSMutableArray *)myMutableTestArray;
[self aTestMethod:self.mutableTestArray];
So I call the method with a NSMutableArray which is an instance variable of the UIViewController. Inside this method, I do this:
myMutableTestArray = [NSMutableArray arrayWithCapacity:100];
//... looping & generating some objects and adding them to the array:
[myMutableTestArray adObject:myObject];
Now, I debug it and inside the method myMutableTestArray is fine. There are all objects inside the array. But leaving this method the instance variable mutableTestArray is empty.
So, where is the problem? Anyone an idea?
Note: I know I can access the instance variable with self.mutableTestArray and then everything will be okay, instead using it as a parameter, but I want to know what's wrong with my code.
Thank you in advance & Best Regards.
Parameters are passed by value in Objective-C. Thus, you are creating a copy of a pointer to the object and passing that into the method. When you do myParam = ... new object ...; that resets the copy to point to a new location, but has no effect on the original copy in the caller.
(To reiterate -- you are copying the pointer, not copying the object.)
To solve, declare your test method as returning an object:
- (NSMutableArray *)aTestMethod;
Then, you can simply:
self.mutableTestArray = [whateverObject aTestMethod];
(Since you aren't actually using the value passed in in the first place, there is no need for a parameter at all).
By your command
myMutableTestArray = [NSMutableArray arrayWithCapacity:100];
you are creating new allocation of mutableTestArray. So passing mutableTestArray as parameter to aTestMethod:
[self aTestMethod:self.mutableTestArray];
is useless because you override its value immediately when create this array inside your aTestMethod.
Try to create your array before passing it to your method (where you will fill it with data).
Remember that parameters are transmitted by value, so in aTestMethod: you are modifying not the original pointer but a copy of it!
For this to work, you should pass the address of the pointer as in
self aTestMethod:&(self.mutableArray)
then the prototype of the method should be
-(void)aTestMethod:(NSMutableArray **)myArray
and in the code of it you should used *myArray as in
*myArray = [[NSMutableArray alloc] init];
Yours, JB
The reason I am doing dynamic class loading is because I am creating a single set of files that can be used across multiple similar projects, so doing a #import and then normal instantiation just won't work. Dynamic classes allows me to do this, as long as I can call methods within those classes. Each project has this in the pch with a different "kMediaClassName" name so I can dynamically load different classes based on the project I'm in:
#define kMediaClassName #"Movie"
Here is the code I am using to get an instance of a class dynamically:
Class mediaClass = NSClassFromString(kMediaClassName);
id mediaObject = [[[mediaClass alloc] init] autorelease];
Then I try to call a method within that dynamic class:
[mediaObject doSomething];
When I then type this into Xcode, the compiler shows a warning that the class doesn't have this method, even though it does. I can see it right there in my Movie.h file. What is going on? How do I call a method from a dynamically instantiated class?
And what if I need to pass multiple arguments?
[mediaObject loadMedia:oneObject moveThe:YES moveA:NO];
Thanks for the help in advance.
you can declare a protocol, like so:
#protocol MONMediaProtocol
/*
remember: when synthesizing the class, you may want
to add the protocol to the synthesized class for your sanity
*/
- (BOOL)downloadMediaAtURL:(NSURL *)url toPath:(NSString *)path loadIfSuccessful:(BOOL)loadIfSuccessful;
/* ...the interface continues... */
#end
in use:
Class mediaClass = NSClassFromString(kMediaClassName);
assert(mediaClass);
id<MONMediaProtocol> mediaObject = [[[mediaClass alloc] init] autorelease];
assert(mediaObject);
NSURL * url = /* expr */;
NSString * path = /* expr */;
BOOL loadIfSuccessful = YES;
BOOL success = [mediaObject downloadMediaAtURL:url toPath:path loadIfSuccessful:loadIfSuccessful];
Well it might be there, but the Compiler doesn't know about it because it assumes that mediaClass is just some Class object, but nothing specific. NSClassFromString() is a runtime function and thus can't give the compiler a hint at compile time about the object.
What you can do:
Ignore the warning
Use [media performSelector:#selector(doSomething)];
And btw, this is wrong:
Class mediaClass; = NSClassFromString(kMediaClassName);
it should be:
Class mediaClass = NSClassFromString(kMediaClassName);
An easier and fancier solution than NSInvocation :)
Class mediaClass = NSClassFromString(kMediaClassName);
if(mediaClass){
id mediaObject = class_createInstance(mediaClass,0);
objc_msgSend(mediaObject, #selector(doSomethingWith:andWith:alsoWith:), firstP, secondP,thirdP);
}
Explanation:
class_createInstance(mediaClass,0); does exactly the same as [[mediaClass alloc] init];
if you need to autorelease it, just do the usual [mediaObject autorelease];
objc_msgSend() does exactly the same as performSelector: method but objc_msgSend() allows you to put as many parameters as you want. So, easier than NSInvocation right? BTW, their signature are:
id class_createInstance(Class cls, size_t extraBytes)
id objc_msgSend(id theReceiver, SEL theSelector, ...)
For more info you can refer the Objective-C Runtime Reference
As Joe Blow says, NSInvocation will help you here, though NSObject has a couple of shortcut methods that you can use: -performSelector:, -performSelector:withObject:, and -performSelector:withObject:withObject:.
I have a subclass of NSManagedObject Class used with Core Data in iPhone. However, I have a temporary "field" (ivar) that I want to add in that Class (but I dont want to persist it in the data-store). Tried to use informal and formal protocol, but both of them give me a "static-variable" like behaviour. (It behaves like a Class Variable rather than Instance Variable). Any suggestion?
My first attempt, created Test "Dummy-class" which is supposedly a subclass of NSManagedObject, then I created Test-category
#interface Test (custom)
NSString *_string ;
- (void)setString:(NSString *)newString;
- (NSString *)string;
#end
Those are the usual setter and getter. This is the way I use the Test class
Test *a = [[Test alloc] init];
Test *b = [[Test alloc] init];
[a setString:#"Test1"];
NSLog(#"%#", [a string]); //This will print out Test1
[b setString:#"Test2"];
NSLog(#"%#", [b string]); //This will print out Test2
NSLog(#"%#", [a string]); //Unfortunately, this will also print out Test2
I could also mess with the NSManagedObject subclass (which is my Entity) directly but I dont think that is the way to do it.
You can't add an instance variable in the (in)formal protocol or in the category.
Any variable definition inside the category is treated as a variable definition at the file level outside the category, so it behaves like a class variable. It's a confusing behavior; I guess the compiler should warn about it.
The standard solution is to add the ivar which holds transient data (which does not persist in the database) in the subclass representing the entity directly, as in:
#interface MyEntity:NSManagedObject{
NSString*stringHoldingTransientSomething;
}
...
#end
and then specifying MyEntity as the class in the Core Data Editor. Note that Core Data does not automatically save ivars in your custom NSManagedObject subclass; it only saves the properties specified in the Core Data model. So you can add as many book-keeping ivars as you want in your custom subclass.
Alright, so I think I'm doing this the right way. I'm new to objective-C, so I'm not sure about the syntax... I have a set of code that I need to call multiple times, from different files. So I made a new class that has a method in it that I'll call and pass it the values that it needs.
Because I am passing different values I've put them in a dictionary and decided to just pass the dictionary. Here is that code:
NSNumber *testNum = [NSNumber numberWithInt:varMoney];
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:#"OMG, Object 1!!!!" forKey:#"1"];
[dictionary setObject:#"Number two!" forKey:#"2"];
[dictionary setObject:testNum forKey:#"3"];
This code creates a test variable, and then puts it into the dictionary "dictionary." That all works, I have my nice little dictionary. However, now I need to create the class and it's method that will recieve the dictionary, and do something with it.
This is my class header file:
#import <UIKit/UIKit.h>
#interface EndOfTurnObjC : UIView {
}
#end
And this is the implementation file:
#import "EndOfTurnObjC.h"
#implementation EndOfTurnObjC
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
}
return self;
}
- (void)dealloc {
[super dealloc];
}
#end
I haven't created any of the real code, because I'm not sure how to do the passing. I need to create a function (Method?) in the class that will take a Dictionary has a parameter, and then return the dictionary.
I also have no idea how to call such a function because it's in the class. So, the questions are:
1: How do I define the method in the class to accept the dictionary as a parameter (and then perhaps some example code to pull out one of the objects in a dictionary, so I can be sure it works)
2: How do I return the dictionary at the end of the method?
3: How do I call this method, in the class, from another class? (I know it involves making an object of thing class and calling the method of the object... I think, but I'm not sure about the syntax.)
Please include relavent code for the 3 files (header, implementation, and the other class that I call from). Thank you so much, I've been working on this particular problem for a while now.
Apple's The Objective-C Programming Language is a good and pretty concise reference for Objective-C syntax. What you want is just a normal method that takes an NSDictionary as a parameter. So as given in that document:
A message with a single argument affixes a colon (:) to the selector name and puts the argument right after the colon. This construct is called a keyword; a keyword ends with a colon, and an argument follows the colon, as shown in this example:
[myRectangle setWidth:20.0];
So a method call to pass dictionary would look like:
[someObject setAttributes:dictionary];
In the header:
-(NSMutableDictionary *) doSomethingWithDictionary:(NSMutableDictionary *) aDict;
in the implementation:
-(NSMutableDictionary *) doSomethingWithDictionary:(NSMutableDictionary *) aDict{
//do something with the dictionary
return aDict;
}
To call the method:
NSMutableDictionary *returnDict=[EndOfTurnObjC doSomethingWithDictionary:dictionary];
Note that as a matter of good design you wouldn't want to pass a mutable dictionary around like a token. That is asking for trouble. Instead pass static dictionaries and get another dictionary back.
You also shouldn't be passing data to a UIView. Instead, your UIViewController should process the data and then populate the view's UI elements as needed.
if you just want to do stuff to your dictionary u just
-(void) changeMyDictionary:(NSMutableDictionary * ) dictionary_
{
[dictionary_ doStuff];
....
...
}
no need to return the dictionary.