I have understandably attracted some smart ass answers to some bone head questions I have asked lately due to my complete misunderstanding of obj c and NSMutable arrays. So I've looked in a book I have and Google and it would appear that may be I shouldn't program because I'm still stuck.
Say I'm looping through method A and each loop through I want to add a double into a NSMutable array. This is what I've discovered so far.
You can't put primitives in arrays, so I made my double into a NSNumber object
NSNumber *newObject = [NSNumber initWithDouble:doubleNumber];
XCode warns: 'NSNumber' may not respond to '+initWithDouble:'
and when I compile it get:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSNumber initWithDouble:]: unrecognized selector sent to class 0x1ffea0'
I ignore that and forge on. Some one told me I need an init method for the array, which makes sense because I don't want that happening in the loop. This is my init method:
-(id) init{
[super init];
arrayOfTouches = [[NSMutableArray alloc] init];
return self;
}
I haven't got to try to add it to the array yet.
[arrayOfTouches addObject:newObject];
Will this work to print out the array.
NSLog(#"array: %#", touchBeginObj);
Bonehead questions, probably. But damn if I can find anything that has all the pieces about what you can and can't do with an good example.
Thanks for any help or smart ass comments.
Yes, I have a Obj-C book, 3 actually and yes I'm reading them :)
Have a good weekend.
NSNumber *newObject = [NSNumber initWithDouble:doubleNumber];
You’re missing the +alloc call in the above code, which is why it’s throwing that error—but why not just use:
NSNumber *newObject = [NSNumber numberWithDouble:doubleNumber];
It’s autoreleased, so you don’t have to worry about releasing it later.
I’m not sure what either of the other questions are asking, could you possibly rephrase them? From the code you’ve given, I think it should work
First :
[NSNumber numberWithDouble: double]
instead of
[NSNumber initWithDouble: double]
Your addObject looks fine.
You have several ways to print your array, I'd suggest iterating, as it will be useful later:
for (NSNumber *number in arrayOfTouches)
{
NSLog(#"Number %f", [number doubleValue]);
}
initWithDouble is an instance method, you're looking for the class method numberWithDouble.
Change this:
NSNumber *newObject = [NSNumber initWithDouble:doubleNumber];
to this:
NSNumber *newObject = [NSNumber numberWithDouble:doubleNumber];
-initWithDouble is an instance method of NSNumber (so you would need to do [NSNumber alloc] first). +numberWithDouble is a class method.
You need to have zero warnings from the compiler - you can't ignore them and 'forge on'.
You are struggling with the basics, do you have experience of other programming languages?
There are a few things you must know in order to code in Objective-c and you must be familiar with the general concepts of object-oriented programming. Also a little C can be helpful as objective-c is an extension to C and it can give some perspective as to why object orientation is so useful and worth-the-effort.
If you already know a language like Python, Java, or even Actionscript then pretty much all of the concepts are the same and objective-c really isn't that difficult. You just need the specifics on how those concepts translate into objective-c. For example,
How do you define a class? How do you override an existing class? What does an initializer method look like? How do you create an instance of a class? etc. There are a few more things than this, but really not that many - you need to learn them, or at least have references at hand in the beginning so you don't go wrong. If you don't know what they mean then you need to learn that.
A 'Class' is like a blueprint for the layout of a piece of memory, in the case of NSNumber a piece of memory that we would hope is going to hold a number. The NSNumber Class knows how big the memory has to be and how it should be laid out. We really care little about the blueprint, the Class - we want an actual chunk of memory that can hold a number - an instance of the Class.
In objective-c creating an object, an instance, of a given class always, everytime, always, always involves -- firstly -- claiming ownership of a free chunk of memory with the correct size, saving the address of that chunk of memory to a variable, then giving the object a chance to do it's own initial setup by calling it's preferred setup method.
To claim ownership of the memory you send the alloc method to the class.
NSNumber *myNumberVariable = [NSNumber alloc];
To set the number up with the initial value of 10.0 you send the message initWithDouble: to your new instance.
[myNumberVariable initWithDouble:10.0];
For convenience these can be, and usually are combined into one statement.
NSNumber *myNumberVariable = [[NSNumber alloc] initWithDouble:10.0];
This is the most fundamental aspect of objective-c programming. You cannot do anything without thoroughly understanding this. Googling init objective-c returns literally hundreds of tutorials, guides, cheat-sheets and help.
If your own Class needs a property initializing when an instance is created, like your arrayOfTouches, you must override the preferred setup method of the parent Class. If the parent Class is NSObject, NSObject's preferred setup method is init. If you create an object in your setup method you must always have a dealloc method. This will always, always, all of the time look like this:
- (id)init {
self = [super init];
if(self){
}
return self;
}
- (void)dealloc {
[super dealloc];
}
Only the name "init" will change, depending on the name of the method you are overriding, - (id)init becomes - (id)nameOfMethodIAmOverriding and [super init] becomes [super nameOfMethodIAmOverriding];
Given this standard template for setup and teardown you can add in the setup and teardown of your own properties. In your case giving you.
- (id)init {
self = [super init];
if(self){
arrayOfTouches = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc {
[arrayOfTouches release];
[super dealloc];
}
Look, it's not that i think you have Boneheaded questions, they are sensible questions but if you have 3 books - the answers are almost certainly on the first few pages of each book - maybe you are going about learning this wrong. Somehow you are not getting the fundamentals. The best i can suggest is to go more slowly and do the exercises in the book, Or choose a simpler language and attempt to master that before moving to objective-c.
Go to Help-->Developer Documentation
Search for NSNumber. Under class methods you'll find how to create a NSNumber with a double.
Related
New to ios and trying to return an NSString from an function. As I understand, I need to [NSString... alloc] init] in order to create the string for return. Also, since I called alloc, I guess I have to autorelease the object myself however I'm getting the message "ARC forbids explicit message send of 'autorelease'" so.. how do I tell ios when I'm done with that allocated NSString?
- (NSString *) generateUID
{
char foo[32];
// create buffer of all capital psuedo-random letters
for (int i = 0; i < sizeof(foo); i++)
foo[i] = (random() % 25) + 65; // 0-25 + CAPITAL_A
NSString *uid = [[NSString alloc] initWithBytes:foo length:sizeof(foo) encoding:NSASCIIStringEncoding];
NSLog (#"uid: %#", uid);
return (uid);
}
ARC = automatic reference counting = the compiler adds the necessary releases and autorelases based on its analysis of your code. You don't see this of course because it happens behind the scenes. As mentioned by sosbom in his comment, you really should read the applicable documentation on the Apple website.
You don't.
autorelease is just there for compatibilities sake, prior to iOS 5, you'd have to do:
Thing *myThing = [[Thing alloc] init]; // Retain count: 1
[myArray addObject:myThing]; // Retain count: 2
[myThing release]; // Retain count: 1
With the above code, the responsability of holding the object is given to the array, when the array gets deleted, it will release its objects.
Or in the case of autorelease.
- (MyThing*)myMethod
{
return [[[MyThing alloc] init] autorelease];
}
Then it would release the object once it gets to a NSAutoReleasePool and get removed once drained.
ARC takes care of that now, it pretty much inserts the missing pieces for you, so you don't have to worry about it, and the beauty of it, is that you get the advantages of reference counting (vs garbage collector), at the cost of an increased compile-time checking to do the ARC step, but your end users don't care about compile-time.
Add to that, that you now have strong and weak (vs their non-ARC siblings retain and assign, the later one still useful for non-retained things), and you get a nice programming experience without tracing the code with your eyes and counting the retain count on your left hand.
Short answer is you don't! ARC will handle the memory management for you.
When ARC is turned on, the compiler will insert the appropriate memory management statements such as retain and release messages.
It is best to use ARC as the compiler has a better idea of an object's life cycle and is less prone to human error.
One other important thing to note about ARC. ARC is not the same as traditional garbage collection. There is no separate process or thread running in the background, like java's GC, which deletes objects when there is no longer a reference to them. One could view ARC as compile time garbage collection :).
The only other thing to be aware of is reference cycles and bridging pointers/objects between Objective-C and Obj-C++/C. You might want to look-up http://en.wikipedia.org/wiki/Weak_reference
Hope this helps
In general, you should define a constructor method in your class and put the alloc logic in that method. Then, it is much harder to make a type casting error as the alloc/init approach always return (id) and it is not very type safe. This what built-in classes like NSString do, like [NSString stringWithString:#"foo"], for example. Here is a nice little block you can use to write code that works both with older non-arc compilation and with arc enabled.
+ (AVOfflineComposition*) aVOfflineComposition
{
AVOfflineComposition *obj = [[AVOfflineComposition alloc] init];
#if __has_feature(objc_arc)
return obj;
#else
return [obj autorelease];
#endif // objc_arc
}
You then declare the method and create an instance of the object like so:
AVOfflineComposition *obj = [AVOfflineComposition aVOfflineComposition];
Using the above approach is best, as it is type safe and the same code with with arc vs non-arc. The compiler will complain if you attempt to assign the returned object to a variable of another type.
I don't know how to release an Objective-C object that I have stored in an old-fashioned c-array.
(Remark: While writing this after much searching, I think I found a bug in the test-code so this seems to be a solution rather than a question. Well, I've spent a lot of time on it so I'll post it anyway...)
I'd like to convert older code to ARC, because I am spending too much time on debugging memory-management related bugs (sorry---the retain/release rules simply aren't hardwired in my spine, and it takes me literally hours to find a missing retain, because the errors pop up at unrelated moments, probably during or after memory cleanup).
So I have some existing code with c-style arrays (say a two-dimensional array of UILabel*'s), where I can happily calloc() the pointers and access them through some array[col*colstride+row*rowstride], where array is of the type UILabel **; Let's assume the UILabel*s are filled at random order, so I can't use an NSMutableArray for that.
Now in ARC, the compiler wants me to make the type of array to be UILabel *__strong*, it seems (some people write that as __strong UILabel **).
What I don't understand is how I can tell ARC to release the UILabel objects when it is time to do so (say in the dealloc() of my object that uses the c-array). In trying to understand the problem, I have a small set of objects, Memory and MemoryUnit, the former trying to store a large c-array of the latter.
-(Memory*)init {
self = [super init];
if (self) {
MemoryUnit * unit = [[MemoryUnit alloc] init];
array = (__strong id *) calloc(sizeof(MemoryUnit*), 1024);
array[0] = unit;
}
return self;
}
-(void)dealloc {
for (int i=0; i<1024; i++) array[i]=nil;
free(array);
}
In MemoryUnit we have the objects to be stored in the c-array (so this MemoryUnit is in the place of the UILabel mentioned above). For testing I had the code
-(void)dealloc {
NSLog(#"removed %x", (int)self);
}
in its dealloc() for debugging.
As Bryan said, we need an answer in the stack overflow system.
So I do:
Solution
Apparently, setting the array element of type MemoryUnit *__strong to nil causes the object to be released, as if this element had been declared in a #propetty and #synthesize pair of statements. This is actually suggested in C-style array of pointers to Objective-C objects under ARC I think
(I found the documentation in XCode very terse, and the ARC compiler definitions only told me what was not allowed rather than giving a hint on how to do things correctly.)
This is a basic question, and I'm not really sure what to search for to see if its been asked before.
In a lot of examples, I've seen property assignments handled like this:
NSArray *tempArray = [/*some code to get array*/];
self.propertyArray = tempArray;
[tempArray release];
Why not just do:
self.propertyArray = [/*some code to get array*/];
What's the difference between the two?
This answer is assuming your not using ARC.
The first code snippet, is the way Apple recommends initializing a property as long as you are doing this in any method besides init. You'll notice Apple code snippets do this a lot. It makes it much easier to manage your memory, and in my opinion it makes it easier to read.
NSArray *tempArray = [[NSArray alloc] initWith....]
self.propertyArray = tempArray;
[tempArray release];
The second code snippet you have could potential lead to a memory leak depending how you set up the NSArray.
This would be a leak. The propertyArray would have an retain count of 2. After you release the instance variable in dealloc, you still have a retain count of 1. That is a leak.
self.propertyArray = [[NSArray alloc] initWith...];
This would be okay, because they both are being autoreleased, which would give you a retain count of 1. As, long as you release the instance variable in dealloc.
// Class Method so autoreleased
self.propertyArray = [NSArray arrayWith....];
// Explicitly declaring autorelease
self.propertyArray = [[[NSArray alloc] initWith.....] autorelease];
It's simply just a matter of preference. I prefer the first way, I think it is easier to to read and follow.
Edit (with ARC):
All these methods would be acceptable with the exception of the release statement and autorelease statement.
[tempArray release];
ARC automatically takes care of the memory management for you, so you do not have to explicitly release them. This is the benefit of ARC, you can create as many objects as you want without the headache of trying to figure out where to release them.
Also, your property would be different. You must either use strong or weak, and not retain. In this case strong would be the solution.
#property (nonatomic, strong) NSArray *tempArray;
In the second example, you don't release the object, which is retained by the property, so you have a memory leak.
self.propertyArray = [[SomeClass alloc] init];
// ^ no release
With ARC, the two statements are equivalent in practice (although you would have to omit the release call for it to actually compile in ARC).
In a manual managed memory scenario, you would leak tempArray in the second ("direct assignment", which it isn't because you're calling a property setter not setting an ivar) example, as you do not have a release call on tempArray to balance it's alloc/init.
The the useful distinction is reduced to expressiveness, the ability to debug, and ultimately the programmers personal preference.
Your first example is the way it was done before the advent of automatic reference counting (ARC). The second example works fine under ARC. Unless you have to do it the old-fashioned way, select ARC for all your projects.
Code like that most likely means that somebody wanted an ability to debug it easier. Basically if you have a separate variable, you can print it out in the debugger without triggering (possibly custom) property setters and getters.
I recently started out with iOS programming (with the Stanford CS193P lectures from iTunes U). I got stuck with the homeworks, that dreaded calculator is a bit too hard for me at the moment, so I started writing little, extremely simple applications to get used to the syntax and data structures in Objective-C.
I wrote a small application which has two buttons.. One 'initializes' an array and fills two UILabels with a) the first object (objectAtIndex:0) and b) the count. I then have a button which allows me to cycle through the array.. showing the next object in there when I click, and of course going back to the very first when I reach the end of the array.
This is easy. I know. But alas, I don't get any feedback like a real Stanford student would, and reading books don't really make me feel okay either. So I would like to ask for some feedback and possible code-improvements, best practices, etc. here.
I created a model with one method, which creates a list of items. I then send retain to it, because I was getting EXC_BAD_ACCESS problems without it; so here my first question: is this okay? :) I didn't think I had to retain it at first, and I still don't exactly understand why it works when I do in fact retain it. Or would it be better to somehow return this and 'catch' it in the controller? I really am not sure what the 'good' way is here.
-(void)populateItemsList
{
itemsList = [NSArray arrayWithObjects:#"Test", #"Test2", #"test3", nil];
[itemsList retain];
}
On to the next piece of code in my Controller:
I lazily instantiate my model here, because I learnt how to do this from the Stanford Calculator assignment. I suppose this is okay to do? I understand that this way, the memory for the model doesn't come in use until it's actually required?
- (DisplayerModel *)model
{
if(!displayerModel)
{
displayerModel = [[DisplayerModel alloc] init];
}
return displayerModel;
}
I then have a method to 'create' the array and populate my outlets (two UILabels, as mentioned before).
- (IBAction)createArray:(UIButton *)sender
{
[[self model] populateItemsList];
arrayCount = [[[self model] itemsList] count];
stepper = 0;
NSString *firstObject = [[[self model] itemsList] objectAtIndex:stepper];
countDisplay.text = [NSString stringWithFormat:#"%d", arrayCount];
display.text = [NSString stringWithFormat:#"%#", firstObject];
}
I'm honestly not sure about this code. It might just be me though, because I'm not really used to writing code in Objective-C; are there any improvements I could make here? I'm especially concerned about the whole stepper idea. I was looking for something like currentIndex or similar, but I couldn't seem to find it in the documentation.. that's why I created the stepper variable to keep track of where I am in the array.
And then finally, the method that makes me cycle through:
- (IBAction)showNextValue:(UIButton *)sender
{
if (stepper == arrayCount - 1) {
stepper = 0;
}
else {
stepper ++;
}
display.text = [NSString stringWithFormat:#"%#", [[[self model] itemsList] objectAtIndex:stepper]];
}
I'm not putting my dealloc or viewDidUnload overrides here because well.. I tested this application with Leaks and it doesn't seem to leak any memory. Are there other ways to test this? Build and analyze doesn't report any problems either. Are there other pitfalls I have to look out for?
Thanks to anyone who's willing to look through my code and provide me with some advice, etc. Still learning!
By convention, class methods using the class name at the beginning return an autoreleased object. Whereas, alloc/init or new return an object with a single retain count.
Thus:
foo = [[NSArray array] retain];
foo = [[NSArray alloc] init];
foo = [NSArray new];
are all equivalent and create an object (an empty array) with a retain count of 1
Lazy creation of needed objects is generally a good practice. It's also good to release those things in a variety of situations, viewDidUnload and memory warnings are two common places for that. If you do that, you might want to save the state in some way - often NSUserDefaults.
The stepper variable is perfectly fine. You could encapsulate it within your model if you wanted to. But in the controller is an acceptable location as well.
Looks pretty good. NSArray doesn't have anything like a currentIndex. An array just contains elements. The same array can be referenced by many objects. If two objects x and y use an array a, a can't keep track of currentIndex for users x and y separately. It's the responsibility of x and y to have its own stepper, as you did.
To optimize a bottleneck, I converted the creation of a large NSArray to a c-style array. (The resulting creation was 1/8 the time of the original NSArray version. Yeah!) But once it's created, speed is no longer an issue, so I'd rather benefit from it being an NSArray again.
However, it seems ridiculously involved to convert a c-style array to an NSArray (unless I'm missing some magic initWithArrayWrapElementsInObjects method.)
As I understand the process now, I first have to create an NSMutableArray, iterate through the c-style array converting each element (floats in my case) to objects, adding each object to the NSMutableArray, then creating the NSArray with the NSMutableArray.
Is that right? There's got to be a better way.
And help would be appreciated.
Thanks!
There's no direct way to take a blob of memory that you own and "convert" it cheaply into an NSArray-- after all, the framework would need to then own that memory, and it doesn't know where you got it from (malloc, stack, etc). If there were a convenience method for initWithArrayWrapElementsInObjects, it would itself need to do internally what you surmise: iterate over your provided memory and add items to itself (it's possibly the framework could do this as quickly as a memcpy, but who knows).
One way you could tackle this (and probably a fun learning exercise) is by actually creating your own subclass of NSArray that manages memory exactly as you want (ie, lets you create and init with whatever semantics you want), but that behaves to the outside world as an NSArray would. You can do this by inheriting from NSArray and implementing the methods count: and objectAtIndex: to operate on whatever memory you're holding on to. Obviously, you'd need to implement the management of your own memory in the init/dealloc, etc methods as well. See this page http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html
under "Subclassing Notes".
The design discussion here hinges on what your data looks like. NSArray, of course, expects its items to be Obj-C references (of type id), and not just arbitrary chunks of data. If your C-style array is holding structures or some other primitive values that aren't object references, then this technique won't really work for you-- NSArray's interface will never be happy with non-reference items.
One final note: you mention taking an NSMutableArray and "creating" an NSArray with it. You should be aware that an NSMutableArray is already an NSArray, since it's a subclass. You can use an instance of NSMutableArray anywhere you'd want an NSArray, without creating some new copy of it.
UPDATE: Missed the note about your array containing floats. Yeah, you're a little bit screwed here. NSArrays want objects. If the capacity doubling was the expensive part (as another poster notes), then try initWithCapacity:. If it's the boxing/unboxing of the floats into object types, there's nothing you can do.
I have created (but don't have handy) a pair of very simple classes (called like MYArray and MYMutableArray) that are intended to wrap just this kind of data with NSArray-like methods on them. But they're not interchangeable with NSArrays. You must use them intentionally.
UPDATE #2. I know it's been ages since this question was live, but I just revisited it and realized there actually is a sort of clever way around this in this specific case. (You want a non-mutable NSArray from a C-style float array). You can create a custom subclass of NSArray that wraps the float values and only converts them to objects when they're accessed via the primitives. This may have performance pitfalls in some corners (?), but it does neatly meet your requirements:
#interface FloatProxyArray : NSArray
{
float * values;
NSUInteger count;
}
- (id)initWithCArray:(float *)arrayOfFloats count:(int)numberOfValues;
#end
.
#implementation FloatProxyArray
- (id)initWithCArray:(float *)arrayOfFloats count:(int)numberOfValues
{
if ((self = [super init])) {
values = (float *)malloc(numberOfValues * sizeof(float));
if (!values) {
[self release]; return nil;
}
memcpy(values, arrayOfFloats, numberOfValues * sizeof(float));
count = numberOfValues;
}
return self;
}
- (void)dealloc
{
free(values);
[super dealloc]
}
- (NSUInteger)count
{
return count;
}
- (id)objectAtIndex:(NSUInteger)index
{
if (index >= count) {
[NSException raise:NSRangeException format:#""];
return nil;
}
float val = values[index];
return [NSNumber numberWithFloat:val];
}
#end
(N.B. Written in the editor without compiling/testing.)
One optimization that you can do with the NSMutableArray is initWithCapacity which will prevent the doubling of your array which is the expensive operation in the addition.
Outside of that, since NSArrays and NSMutableArrays expect objects, so it's difficult to get around this.
What benefits of it being an NSArray are you looking to get?
It seems like you may be better off with a custom wrapper object around the C array that responds to whatever NSArray messages you are looking to call. Otherwise you are right back at the point of array creation... You could try manually creating a call to initWithObjects, but at the very least every float has to be wrapped in an NSNumber which would bring down your speed again.
If you really need an NSArray because something else you want to use takes NSArray objects, then you are probably better off subclassing NSArray (following the guidelines posted by Ben).
The “best” optimisation (for speed) would almost certainly be to avoid using NSArray altogether, if possible.