Elegant ways to use Objective C while developing an iOs / OsX application? - objective-c

I've been developing iOs and OsX applications for several months now and it still feels like I'm doing something wrong. I try to stick to the Guidelines and I try to use the objects Apple provides as often as I can. But it seems they are making my code very hard to understand.
Example:
When I want to just "increment" a NSNumber Object (which is not mutable, but you get what I mean), I use awkward lines like this:
int value = [counter intValue];
counter = [NSNumber numberWithInt:value +1];
Is this really necessary? Are there more elegant ways (i++, inc(i), etc) to do simple things like this? Especially when you're working with coordinates it gets really frustrating and hard to work with.
When working with Objective C I feel like I'm allocating, deallocating and converting objects all the time and wasting so much of my own time and the CPU time with all those conversions. Thanks for your time, I really appreciate your answers and I'm looking forward to your tipps!

Using your example, is there any particular reason you are using NSNumber for a counter? It would be much better to use int so that you can use value++.
The key to good Objective-C code is to use objects when they make sense. Don't be afraid to use non-object data types and don't be afraid to drop down (not the best term) to C when required.

As #sosborn wrote: use objects only when it's required. But: when it's required, and you still feel wrong, simply don't. Write a macro for incrementing an NSNumber, use ARC for let the compiler do the memory management for you as efficiently as possible, etc. If you really worried about time, use C or assembly for time-critical tasks, or C++ if you want OO.
P. s.: NSNumber increment macro:
#define NSNUM_INC(n) do { n = [NSNumber numberWithInt:[n intValue] + 1]; } while (0);

You can write your category for NSNumber to implement the methods you need. For your example the file of category contains the following function:
-(NSNumber *)numberByAddingInt:(int)i
{
...
}
Include this file and then you can call it as:
counter = [counter numberByAddingInt:1];

Related

Objective-C initWithInt vs. numberFromInt vs. simply #number?

Quite new to Objective-C, as I just started researching on an old macOS project for a client. One thing I noticed is that it seems when initializing/assigning an int value to an NSNumber object in Objective-C, there are different ways to do it, for example:
NSNumber *a = [NSNumber numberWithInt:10];
NSNumber *b = [[NSNumber alloc]initWithInt:10];
NSNumber *c = #10;
As far as I can see, they all do the same thing, and the last line is the easiest to type and read, while the second line is just way too convoluted IMHO, so I'm just wondering are there any real differences in the end results from those three different methods, or situations where one specific method should be used because the others won't work?
There is a difference between a & b which was important before ARC when memory management was manual, but today with automatic memory management is essentially irrelevant to the programmer as ARC handles the difference seamlessly.
In pre-ARC days a references a number object which is not owned, while b references one which is owned, and the manual management required for each is different and the programmer needs to know that.
In post-ARC days the management is automatic and the programmer generally does not need to know the difference.
Option c is a shorthand for a that was introduced later and is now the standard way of creating NSNumber objects from literal values. The form #(<expr>) is also provided to create an object from the result of evaluating an <expr>.

Objective C : can't operate download issue

i'm new to Xcode objective-c and I have a task to make a newsletter that downloadable.
So, I got some source code and tweak a bit but I got some error that said
"Implicit conversion loses integer precision : 'long' to 'int'
here are my code
-(void)downloadIssue:(IssueInfo*)issueInfo{
NewsstandDownloader* downloader = [[AppDelegate instance] newsstandDownloader];
downloader.delegate = self;
long index = [self.publisher indexOfIssue:issueInfo];
[downloader downloadIssue:issueInfo forIndexTag:index]; <-- Error
}
Please help me.
Thank you.
That's just a compiler warning and a mild one at that. If you were dealing with a document that had more than, say, 32000 pages then you might need to be concerned about it.
The way to solve the problem is to either change the declaration of the function you're calling to something like:
[downloader downloadIssue:(IssueInfo *)issueInfo forIndexTag:(long)index]
or, simply use a cast:
int index = (int)[self.publisher indexOfIssue:issueInfo];
"int" isn't usually a good thing to use in Objective C as there are different lengths and capacities to it on different platforms (32 bit versus 64 bit, iOS vs MacOS, etc.). It's better to use something more Objective-C specific, like NSInteger or NSUInteger.

ObjC structs of floats in arrays: Compact way to avoid NSValue?

I'm to port some JS to native ObjC code. Since a struct won't fit inside arrays, it needs to be wrapped.
The JS code goes as follows:
var bezierVertices = [{0: 14},{10: 32},{24: 16}];
Plain and easy JS: Array of anonymous objects.
I'm bound to the following requirement: Have the code as compact as possible, meaning I've been refused when proposing an NSArray of NSValue using [NSValue valueWithCGPoint:ccp(x,y)]
Going down the malloc way doesn't fit this criterion either. They want something as compact as the JS stated above.
Before writing something as ugly as an NSString like #"0:14;10:32;24:16"; that's split and parsed in a loop, I thought SO could help bring something clean :)
I'm allowed to use .mm so ObjC++ solutions could fit as well, but I'm not knowledgeable about C++ at all...
Thanks!
J.
They want something as compact as the JS stated above
Who's "they"? Do "they" have any understanding that Objective-C is a compiled language and the "compactness" of the source code is largely irrelevant?
Anyway, rant over. You can make a C array of CGPoints like this:
CGPoint myArray[] = {{0.0, 14.0}, {10.0, 32.0}, {24.0, 16.0}};
This is a standard C array initialiser. You get the number of elements like this:
int nElements = sizeof myArray / sizeof(CGPoint);
If you need to manage variable-length arrays of vertices, C++ provides std::vector<CGPoint>.

Wondering how to deal with nsnumber objects in an arithmatic operation

I saw this thread but wanted to confirm:
How to convert NSNumber objects for computational purposes?
So basically anytime you want to deal with these objects you have to unpack their ivars, and then pack them back up into new objects, presumably NSNumbers?
That seems hella weak(and a large pain in the backside, no?).
How do you folks work with these?
Do you avoid them? Subclass them? is there mutable versions?
This just seems like a lot of work to deal with them, would love to hear their benefits and ways more experienced programmers have used them, or what tactics they have used to avoid using them.
Thanks,
Nick
So basically anytime you want to deal with these objects you have to unpack their ivars, and then pack them back up into new objects, presumably NSNumbers?
Yes. (By the way calling doubleValue does not just mean unpack the ivar. There maybe some conversions too.)
That seems hella weak(and a large pain in the backside, no?).
This "boxing" is necessary because primitive numbers by themselves to not support Objective-C (Foundation.framework)'s ref-counting scheme. For example, you have to box a number as NSNumber in order to store them in an NSArray.
Do you avoid them?
You can't.
Subclass them?
You shouldn't, but if you have to, follow how it's suggested:
As with any class cluster, if you create a subclass of NSNumber, you have to override the primitive methods of its superclass, NSValue. Furthermore, there is a restricted set of return values that your implementation of the NSValue method objCType can return, in order to take advantage of the abstract implementations of the non-primitive methods. The valid return values are “c”, “C”, “s”, “S”, “i”, “I”, “l”, “L”, “q”, “Q”, “f”, and “d”.
If all you want is add some convenient methods e.g. -numberByAddingNumber:, use a category:
#implementation NSNumber (MyExtension)
-(NSNumber*)numberByAddingNumber:(NSNumber*)another {
double myVal = [self doubleValue];
double anotherVal = [another doubleValue];
return [NSNumber numberWithDouble:myVal + anotherVal];
}
#end
...
NSNumber* a, *b;
...
NSNumber* c = [a numberByAddingNumber:b];
...
is there mutable versions?
No.
I avoid NSNumbers when I'm going to have to perform arithmetic on a variable. Actually, I avoid them at all times, unless I'm going to be rolling them into Core Data or something.
Now that there are Objective-C Literals in the newest version of clang compiler (version 3.2 up, came with Xcode 4.6 and also can be built from source), you can do stuff like #42 and #(7+35) to "box" NSNumbers.

How can I remove the first element of an array in Objective C?

In Objective C, is there a one-liner or something small to remove (shorten by one) and return the first element of an array, regardless of its index?
I don't know of a method that returns the item removed, but you can do this using a combination of NSArray#objectAtIndex:0 and NSMutableArray#removeObjectAtIndex:0. I suppose you could introduce a new method category on NSMutableArray that implements a shift method.
That would be a poor thing to do.
Objective-C on the iPhone can actually use most of the performance perks of C.
If you look at some of my other posts, you'll see I'm ADAMANTLY against premature optimization, but when you are coding at the C level, there are just some things you don't do unnecessarilly.
Move memory
Duplicate structures
Allocate sparsely populated memory blocks
Inner loops
... (There are lots more, but my C-life is rusty and, as I said, I'm anti-optimization)
What you probably want is a well-implemented queue. Something that pre-allocates a large enough circular memory structure and then has two pointers that track the first and last bytes.
I'd be pretty surprised to hear that Objective-C didn't have a queue data structure.
Also, don't strive for the one-liners. All the stuff about terse code is overrated. If it makes more sense to call a method, so be it.
It's certainly too late to assist the original poster, but if you have a plain NSArray and not an NSMutableArray, this works well:
id myData = myArray.firstObject;
myArray = [myArray subarrayWithRange:NSMakeRange(1, myArray.count - 1)];
Cocoa array objects (NSArray/NSMutableArray) do not provide a one-line equivalent — you would have to read the object first, then remove it. The fact that these classes provide the methods -lastObject and -removeLastObject but not -firstObject and -removeFirstObject should be a reminder that removing from the front of an array is usually an inefficient operation, since the contents must be shifted (copied) one position forward. This is particular true for arrays in C, which are intrinsically tied with pointers.
If you're working with anything but primitive data types and/or very small arrays, you might want to consider that the behavior of "shifting off" the first element is indicative of a queue data structure. For details on how you might create a queue for objects, see this SO question. Personally, my opinion for that question is that a real queue class provides the cleanest programming idiom. You can even define your own method (perhaps as a category on NSMutableArray or another class) that does provide a one-liner to do what you want:
#interface NSMutableArray (QueueOneLiner)
- (id) removeAndReturnFirstObject; // Verbose, but clearer than "shift"
#end
#implementation NSMutableArray (QueueOneLiner)
- (id) removeAndReturnFirstObject {
id object = [[self objectAtIndex:0] retain];
[self removeObjectAtIndex:0];
return [object autorelease];
}
#end
However, by that point the solution will likely cause more overhead than it's worth, depending on the importance you place on simplicity versus performance of the code that uses it.
If you have an array obj *arr where obj is a class/typename and arr is the array, you can just say arr+1 to get the array without the first element.
Use this code,
[arrayName removeObjectAtIndex:0];
this may help you