Is there any way to create a mutable dictionary with a capacity limit rather than an initial capacity?
Say you want to create a dictionary that will only ever have, at most, 100 entries.
The capacity argument for the dictionary is an initial capacity that will be simply increased if you add more elements than you want so it's not suitable.
Subclass it and override addObject to check count before adding? No built-in way.
Here is a basic example... not tested, missing init etc, but this is the core. You should also override setValue:forKey: in a similar manner.
#interface MyMutableDictionary: NSMutableDictionary
- (BOOL) setObject:(id)anObject forKey:(id)aKey;
#end
#implementation MyMutableDictionary
- (BOOL) setObject:(id)anObject forKey:(id)key {
if ([self count] < yourLimit) {
[super setObject:anObject forKey:key];
return YES;
}
return NO;
}
#end
There is no API for this, but the code to do so is fairly simple:
void AddObjectToArray(NSMutableArray *array, id obj, NSUInteger maxCount) {
if ([array count] < maxCount)
[array addObject: obj];
}
Note that the above code is not thread-safe, but making it thread safe is about as simple as wrapping the function's contents in a #synchronized (array) directive.
If you want an array that can be bandied about and have this limit built-in, don't subclass the NSMutableArray class cluster. NSMutableArray's contract (the "agreement" it has with calling code) says that a call to -addObject: will add that object to the array, not that it will if the array is under a limit.
Rather, an array with a maximum length behaves differently enough from the standard behaviour that it ought not to be a subclass of NSMutableArray. This may seem like a contrivance--it's an array and you can mutate it, therefore it should be treatable as an NSMutableArray. But calling code has no way to know that its modifications will fail silently on your subclass, and will probably not be designed with such failures in mind.
If the calling code is yours, you can use the helper function defined above--you know the objects might not be added and you can code appropriately. If the calling code comes from elsewhere (e.g. Cocoa or other Apple frameworks), use a normal NSMutableArray, and cull it when the calling code is done adding objects.
Related
i have some trouble writing a method in Objective-C to make an object nil. Here is some example :
#interface testA : NSObject
{
NSString *a;
}
#property (nonatomic, retain) NSString *a;
+(testA*)initWithA:(NSString *)aString;
-(void)displayA;
-(void)nillify;
#end
#implementation testA
#synthesize a;
+(testA*)initWithA:(NSString *)aString{
testA *tst=[[testA alloc] init];
tst.a=aString;
return [tst autorelease];
}
-(void)displayA{
NSLog(#"%#",self.a);
}
-(void)nillify{
self=nil;
}
- (void)dealloc {
[a release];
[super dealloc];
}
#end
int main(int argc, char **argv){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
testA *test=[testA initWithA:#"some test"];
[test displayA];
test=nil;
//[test nillify];
NSLog(#"after setting to nil");
[test displayA];
[pool release];
return 0;
}
Apparently , when I set test object to nil and then call some method on it nothing happens , but if i call nillify instead of directly setting it to nil , displayA method works normally like test object is still there. Is there a workaround for nillify method to function properly ?
Your help is much appreciated !
You can't actually do something like this, because setting 'self' to nil only has any effect within the scope of that method (in your case, 'nilify'). You don't have any actual way to effect the values of pointers located on other parts of the stack or in random places in the heap, for example.
Basically any code that holds a reference to some object is responsible for maintaining and clearing those references itself. If you have some use case where random sections of code may need references to "live" objects of some kind, but where you'd want those object references to go away in response to some external event (maybe a user tracking system or something), you could do something with notifications, but the various modules tracking those "live" objects would still be responsible for listening for notifications and cleaning up references when they received them.
The 'nilify' thing, however, can't possibly work.
You cannot do what you're trying to do. self is just a local reference to an object that actually exists elsewhere. Setting it to nil doesn't mean anything. An object doesn't, in general, own itself, and it certainly doesn't control other objects' references to it. It's up to the owning objects to manage its lifetime.
There are a few things wrong with your code.
First, by convention, class names start with an uppercase letter. Please stick to these naming conventions as it will make it harder for other developers to work with your code (and even confuse you).
Next, your initWithName:... According to the naming conventions, a method with init in its name should be an instance method, not a class method. So either name it newWithName: or turn it into an instance method like this:
-(testA*)initWithA:(NSString *)aString{
self = [super init];
if (!self) return nil;
tst.a=aString;
return self;
}
If you keep it as class method (and name it newWithName:) you should not return a autoreleased object since according to the naming conventions method that start with init... or new... return a retained object. If you do not follow these conventions, the static analyzer will give you "false" warnings and it will become useless for you.
Now for the reason your nillify doesn't work: the self is in fact an argument to a method. Under the hood, your nillify method actually has two arguments that you do not see: the self pointer and the selector pointer. This means, self is actually a variable on the stack. And if you overwrite it, you only overwrite that stack variable but that doesn't influence your test variable which is somewhere else.
As an example, consider a method - (void)foo:(NSString *)bar;. The compiler turns it into the equivalent of the C function (void) foo(id self, SEL _cmd, NSString *bar).
I am newbie to iPhone programming. I have the following doubt which is stopping me to go ahead. Please consider the following code:
---------.h------
#interface myClass: UIViewController
{
UIImage *temp;
}
#property (nonatomic, retain) UIImage *temp;
---------.m------
#interface myClass
#synthesize temp;
-(void) dealloc
{
[temp release];
[super dealloc];
}
The above is the only program code. Thats it ... nothing else. Do I need to declare [temp release] in dealloc method even though I am not using the property accessor method in my program at all. What if I don't declare [temp release] in dealloc. Will that create memory leak as I am releasing something which I haven't retained as I am not calling property accessor method.
Also when i print retain count for temp why does it show 0 even though it is getting retained in #property.
Thanks in advance
If no value has ever been assigned to (an instance of) myClass.temp, then there won't be a leak. But you should release it in your dealloc.
#property is only a declaration that instance of myClass will have this property. You need to assign it a value before that value gets retained.
myClass *instance = [[myClass alloc] init];
// instance will now retain the value passed in
// and is therefore responsible for releasing it
instance.temp = [UIImage imageNamed:#"whatever"];
// if instance is not retained anywhere else,
// its dealloc will be called
[instance release];
On a sidenote, you should give your classes names that start with an uppercase
letter, i.e. MyClass. Not required, but makes things clearer.
You can also use self.temp = nil; in your dealloc You're sorta not supposed but it kinda works better and looks cleaner. It's a bit of an iffy subject...
What you are doing is correct. Scroll to the "dealloc" section of this Apple Doc: Declared Properties
Soon, however, these properties will be cleaned up automatically when you synthesize them (in the next Cocoa update) -- that being said, a convention I have personally began to follow so that my code works in the future is setting self.temp = nil; in dealloc instead of sending a release message (read the apple doc i posted, it explains this). The accessor method created at runtime releases the object first, so for me and quite a few other devs, this is a better/safer way of cleaning up declared properties in our dealloc.
Your code is correct.
The general rule is that, for all variables you declare in #interface, you must clean them up in -dealloc. Some variables will need to be released, others just need to be nil'd out, depending on how you've declared the #property.
In your example above, temp may never have been given a value explicitly by you, but the ObjC runtime will have initialized the value of temp to nil when an instance of your class gets allocated.
Sending a -release to a nil object is generally not a problem, so the [temp release] is fine. It's a no-op. When temp has a non-nil value in -dealloc, the [temp release] gets to do its job of freeing up the memory.
If you need temp to have a non-nil value on creation, you'll need to implement the -init method and make sure it gets some value. While your class is legitimate & functional without an -init method, you really should get in the habit including one in every custom class you design.
You'll need the default initializer at a minimum: -init. You may also want to design a more detailed initializer that could be used to give your temp ivar an a value, like -initWithImage:
Here's what you should also be including in your class:
#implementation MyClass
...
- (id) init {
self = [super init];
if (self != nil) {
// The minimal default initializer.
// temp will already have a value of nil, so you don't need necessarily
// need to do anything more, unless temp needs a real value on initialization.
}
return self;
}
- (void) dealloc {
...
}
#end
To implement a more detailed initializer, which would be known as the designated initializer, you would to something like this:
#implementation MyClass
...
- (id) initWithImage:(UIImage *)newImage {
self = [super init];
if (self != nil) {
temp = [newImage retain];
}
return self;
}
// Implement the default initializer using your more detailed initializer.
- (id) init {
// In this default initializer, every new instance comes with a temp image!
return [self initWithImage:[UIImage imageNamed:#"foobar"]];
}
- (void) dealloc {
...
}
#end
Here, the designated initializer -initWithImage: is the authoritative initializer. All other initializers, including -init, get implemented using -initWithImage:.
You get to exercise a lot of discretion over whether to implement any initializers beyond the minimal default initializer. Maybe -init is good enough for your purposes. That's fine. Sometimes more detailed initializers make using the class more convenient. Experience (and the Force) will be your guide.
Note that I didn't use the generated property accessor in either initializer method. If you aren't required by circumstances, you should generally avoid using property accessors in -init methods and -dealloc, primarily because of potential pain-in-the-ass issues with side effects of automatic key-value coding notifications.
The initializer and dealloc methods play a special role in a class. As the class designer, it is your responsibility to set and clean up instance variables in these methods. A good rule of thumb is to leave the use of synthesized property accessors for the callers of your class, and the implementation of other methods in the class.
When doing initialization of an instance, or deallocation, you can and should touch the ivars directly. They're yours. You declared them, so you can handle them directly. When implementing other methods in your class, you generally should use the property accessors.
JeremyP's link to the Cocoa Conceptual documentation on objects is a good one. You should definitely read the sections on Objects, and periodically re-read it as you gain more experience writing custom classes of your own. Eventually, it will all start making sense.
I have a function That takes by reference any kind of object
-(BOOL)RemoteCall:(id**)DataClass;
in the implementation i use [*DataClass isMemberOfClass:[NSMutableArray class] to find out the type of the object. The problem is it does not work with NSMUtableArrays Does anybody have a solution to this problem ? Here is the relevant code:
Implementation:
-(BOOL)RemoteCall:(id**)DataClass
{
if([*DataClass isMemberOfClass:[NSMutableArray class] ] == YES)
{
NSMutableArray * SW =(NSMutableArray *)*DataClass;
//do something with SW
DataClass= (id**)SW;
return TRUE;
}
}
Any help and I mean anything at all will be appreciated, I'm stuck.
Method Call:
NSMutableArray * channelArray = [[NSMutableArray alloc]init]
Services * serv = [[Services alloc] init];
return [serv RemoteCall:&channelArray];
Pass by reference in Objective-C is almost never the right way.
There are a number of problems with that code.
(id**) is a pointer to a pointer to a pointer to an object. Probably not at all what you want.
YES and NO are BOOL return types; not TRUE
there is no reason in that code to be returning something by reference.
method names start with lower case letters. Arguments do, too.
There will never be an instance of NSMutableArray in an application; just subclasses
You can't tell the difference between a mutable and immutable array in the first place; check for isKindOfClass: or isMemberOfClass: for an NSMutableArray won't do you much good (it is useful, but misleading).
This is better:
-(BOOL)remoteCall: (id) dataThing
{
if([dataThing isKindOfClass:[NSMutableArray class]] == YES)
{
NSMutableArray *swArray = dataThing; // not strictly necessary, but good defensive practice
//do something with swArray
return YES;
}
return NO;
}
To be called like:
NSMutableArray * channelArray = [[NSMutableArray alloc]init]; // you'll need to release this somewhere
Services * serv = [[Services alloc] init];
return [serv remoteCall:channelArray];
Since you don't return a different array in remoteCall:, channelArray's contents will be manipulated by the method and the YES/NO return value.
If there is some reason why the above seemingly won't work for you, please explain why.
Note: The code obviously requires an NSMutableArray if you are going to muck with the contents. The isKindOfClass: could be checking for NSMutableArray or NSArray and it wouldn't matter either way. When using arrays in your code and requiring a mutable array, it is up to you to make sure the data flow is correct such that you don't end up w/an immutable array where you need a mutable array.
If you don't need to reassign your variable, then don't use this. id or NSObject * is just fine and works by reference anyway. id * or NSObject ** would be references. id ** doesn't make sense at all here.
Also, learn naming conventions (like upper/lowercase).
NSArray is a class cluster. That means that every NSArray instance is actually an instance of some subclass. Only isKindOfClass: is useful for class-membership testing with class clusters.
Also... thats horrible code - please accept this:
-(BOOL)remoteCall:(id)dataClass {
if([dataClass isKindOfClass:[NSMutableArray class]]) {
NSMutableArray *sw =(NSMutableArray *)dataClass;
return YES;
}
}
that should work.
Constructive critisism of coding: You need to adhere to coding conventions. Although your code will work... its not brilliant to read and theres a lot of unnecessary *s and such.
Function names should be camel coded with a preceeding lower-case letter as should variable names. Passing (id) into a function doesn't require *s at all. Objects you pass into a function only available throughout the scope of the method anyway and that method doesn't own it, I'm not sure what you're trying to do with all the extra *s, but just treat objects you pass into the method as if you don't own them. :)
As Eiko said before, i'd use just id and not double pointers to ID.
I'm also pretty sure that isMemberOfClass is your Problem. isMember does not check for inheritance, so you're only asking for Top level Classes. isKindOfClass is probably the better choice, as there is no guarantee that Apple doesn't use an internal subclass of NSMutableArray internally. Check the Apple Docs.
i'd write it as such:
-(BOOL)RemoteCall:(id)dataClass
{
if([dataClass isKindOfClass:[NSMutableArray class] ] == YES)
{
NSMutableArray * SW =(NSMutableArray *)dataClass;
//do something with SW
return TRUE;
}
}
I have this code in one of my classes:
- (void) processArray
{
NSMutableArray* array = [self getArray];
. . .
[array release];
array = nil;
}
- (NSMutableArray*) getArray
{
//NO 1:
NSMutableArray* array = [[NSMutableArray alloc]init];
//NO 2:
NSMutableArray* array = [NSMutableArray array];
. . .
return array;
}
NO 1: I create an array and return it. In the processArray method I release it.
NO 2: I get an array by simply calling array. As I'm not owner of this, I don't need to release it in the processArray method.
Which is the best alternative, NO 1 or NO 2? Or is there a better solution for this?
The method should return an autoreleased array, NO 2 is the better choice. The reason for this is that when you call the method with
NSMutableArray* array = [self getArray];
you will expect as a matter of convention to not have to release the array. If you want to take ownership of it, you retain it, but otherwise you shouldn't have to care about it. In Cocoa, you only take ownership by explicitly sending alloc or retain or copy (or new). Since the processArray method doesn't do that, it shouldn't have to take care of releasing the array.
So you should use NO 2, and also you should remove these two lines:
[array release];
array = nil;
If the array and its contents use a lot of memory or its used lots of times, you'll want to release them straight away, so use option 1. According to the Objective-C guidelines, you'll want to prefix the word "new" to your subroutine name instead of "get" in that case.
If on the other hand, you want to reduce the number of lines of code that say simply [array release]; or similar then use option 2.
It is simply a balance between reducing lines of code, and reducing unnecessary temporary memory use.
Whilst the autorelease pool will help in reducing memory leaks and make your code smaller, sometimes you need to explicitly release everything as it goes out of use to keep the use of memory down.
HTH
EDIT
Ah - I stand corrected. Reading the iPhone version of the Memory Management Programming Guide for Cocoa I see that the iPhone guidelines are to use a prefix of "new..." so for example "newArray" in this case, if the caller is supposed to manually release and NOT a prefix of "create...". "Creating" can refer either to creation of manually released or of automatically released objects and so would be ambiguous. Text corrected above.
- (void) processArray
{
NSMutableArray* array = [[self getArray] retain];
//Now you are the owner of array, so you take care to release it
. . .
[array release];
array = nil;
}
- (NSMutableArray*) getArray
{
//create a new array
//temporarily the method owns the array
NSMutableArray* array = [[NSMutableArray alloc]init];
//fill in here with elements or what you want
..........
[array autorelease];
//autorelease here says "I don't own the result
//if anyone cares about it, he should retain it himself
return array;
}
So in short when you create new objects you should autorelease them before returning.
Because if the calling method wants to use the result, the calling method should take care
of retaining and releasing the result.
It's always good to run the Klang static analyzer for this issues, when you are not really sure in your retaining/releasing code : http://clang-analyzer.llvm.org/
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.