Are there standard optimization tricks for Objective-C to make for faster execution along the lines of "inlining" frequent methods as in C++ or the "g++ -fast" tag?
Edit: Does anyone have a short example using SEL and IMP when theMethod has two (or more) integers for input?
Here's a small optimisation that may not really be worth the time to implement, and one that I never use personally, but I guess still good to know about. Rather than repeatedly sending the same message to the same object over and over, you can bypass repeated method dispatch by directly using the method implementation. For example, instead of:
for (int i = 0; i < 100000000; i++)
[someObject messageWithInt:i];
You could try:
SEL theSelector = #selector(messageWithInt:);
IMP theMethod = [someObject methodForSelector:theSelector];
for (int i = 0; i < 100000000; i++)
theMethod (someObject, theSelector, i);
This means that the method lookup is only done once and you can invoke the method directly through the returned IMP value. All Objective-C method implementations take at least two arguments, the first argument is the receiving object of type id, which becomes self within the method implementation, and the second argument is the selector [of type SEL] that was used to determine the method implementation, and becomes _cmd in the method implementation.
This approach can quickly turn sour if you don't use the correct “function definition” (I can't remember the proper term). IMP is a typedef for a function that returns void* and takes (id,SEL,...) as arguments. This can make it troublesome to use if the method actually returns something else like float. To help with this matter, you can cast the return value of -methodForSelector:, like this:
typedef float (*MyMethodIMP)(id,SEL,int);
SEL theSel = #selector(messageWithInt:);
MyMethodIMP theMethod = (MyMethodIMP)[someObject methodForSelector:theSel];
float result = 0.0;
for (int i = 0; i < 100000000; i++)
result += theMethod (someObject, theSel, i);
With some care, you can save the theMethod and you may be able to use it for all instances of a particular class, not just one instance, but tread carefully.
Optimization is best handled by the compiler. Macs use GCC, so the standard optimization GCC flag (-Olevel) should work. In XCode, you can set the optimization level in the project settings. If you're not using GCC, check you compiler documentation for how to enable optimization.
Update: XCode 4 uses the LLVM backend by default. Both the GCC and clang frontends use "-On" optimization flags. For GCC, n is an integer from 0 through 3, or "s" or (Apple only) "z". For clang, n is an integer from 0 through 4, or "s".
Related
I made a member struct that I assigned in the ViewDidLoad of my iOS app. I used malloc to allocate space for this struct that was then used throughout my class. Like this:
self.myData = malloc(sizeof(MyData));
Except what I really did was this:
self.myData = malloc(sizeof(MyOtherStruct));
I accidentally set sizeof() in the malloc call to be a different struct (that isn't the same size). I didn't notice this mistake for a very long time because the app only rarely crashed. An update to the OS caused the crash to happen more frequently.
My question is, why can compiler's not warn about this sort of thing? Is it something compiler's don't know about or is it a design choice to allow users's to malloc whatever size they please?
"How can I find this error faster?"
There are a bunch of ways to find the error faster.
Solution #1
The static analyzer cathes this error. Press command-shift-B in Xcode. For example, take the following code:
#include <stdlib.h>
struct x { double x; };
struct y { char y; };
int main(int argc, char **argv) {
struct x *p = malloc(sizeof(struct y));
p->x = 1.0;
return 0;
}
Running the analyzer produces this error for me:
Result of 'malloc' is converted to a pointer of type 'struct x' which is incompatible with sizeof operand type 'struct y'
Solution #2
It is recommended to write the code this way instead:
self.myData = malloc(sizeof(*self.myData));
Just do it this way in the future. This is not only less error-prone, but it is easier to remember.
Solution #3
Use a language like Swift or C++ where the language's type system help you avoid this kind of error. C is less forgiving in many ways. It was invented in the early 1970s, you just kind of have to accept that if you want to use it, and these kinds of errors are a major part of the reason why C++ and Swift even exist in the first place.
Solution #4
Use a run-time memory bounds checker, like the address sanitizer. This will detect the error when memory is accessed, not when it is allocated, but it will still give you stack traces for both access and allocation (and free, if the memory has been freed). Anyone writing C these days should familiarize themselves with the address sanitizer and its friends, tsan, ubsan, etc.
Valgrind also achieves the same effect but the address sanitizer has a better user experience for common use cases.
Question as asked
The compiler only really gives you errors and warnings for type errors. This isn't a type error, it's a runtime error. There are a few "likely" runtime errors that the compiler can detect, but they are very few in number. Things like forgetting to use the return value of malloc()... e.g.,
void f(void) {
malloc(1); // warning
}
The compiler isn't much better than that.
Again, this is the impetus for newer languages like C++ and Swift, which have type systems which allow you to generate errors when you allocate things incorrectly, and this is also the impetus for static analysis (which is a tough problem).
That happens because is not ARC responsability to deal with malloc() and even free()
The ARC just handle with objects allocated like [Object alloc]
In your case, when you do self.myData = malloc(sizeof(MyOtherStruct));, that can be interpreted for example with something like this:
self.myData = malloc(N*sizeof(MyData));
//what can represents self.myData[0]..self.myData[N-1]
For the last, remember when you use sizeof(), it will tell you about the size of the type, that you are passing as a paramter, calculated in compile-time.
You can check this link for more information about object allocation
And also check Apple Documentation about Memory Alloc
I apologize if this question is exceedingly simple, but I've Googled like crazy and am unable to find a suitable explanation for what this is.
for (id line in self.lines){
[linesCopy addObject:[line copyWithZone:zone]];
}
I'm just learning Objective-C, and this is a form of for loop that I've never seen before. I'm familiar with the simple
for (int x = 1, x < 10, x++)
style of for loop.
From Cocoa Core Competencies: Enumeration:
Fast Enumeration
Several Cocoa classes, including the collection classes, adopt the NSFastEnumeration protocol. You use it to retrieve elements held by an instance using a syntax similar to that of a standard C for loop, as illustrated in the following example:
NSArray *anArray = // get an array;
for (id element in anArray) {
/* code that acts on the element */
}
As the name suggests, fast enumeration is more efficient than other forms of enumeration.
In case you didn't know, id is an Objective-C type that basically means “a pointer to any Objective-C object”. Note that the pointer-ness of id is built in to it; you usually do not want to say id *.
If you expect the elements of anArray to be of a specific class, say MyObject, you can use that instead:
for (MyObject *element in anArray) {
/* code that acts on the element */
}
However, neither the compiler nor the runtime will check that the elements are indeed instances of MyObject. If an element of anArray is not an instance of MyObject, you'll probably end up trying to send it a message it doesn't understand, and get a selector-not-recognized exception.
It's the shorthand equivalent of this common form:
for (int i = 0; i < [self.lines count]; i++) {
id line = [self.lines objectAtIndex:i];
// ...
}
It's such a common looping idiom (walking through some collection, array, set, etc. an item at a time), that it's been turned into a shorthand form like this, called "fast enumeration".
In fact, in its internal implementation, it's actually slightly more faster than doing it yourself, so it's preferable both for clarity and performance.
It's a statement that can be used with classes that are conform to NSFastEnumeration protocol. When you have this available, the Objective-C programming guide suggest you to use it. Take a look here. It's a way to iterate over a collection without the traditional for (int i = 0; i < length; ++i) syntax.
Mind that it doesn't usually support deleting and inserting elements while iterating through this way (also by using normal for loops you should take care about indices in any case).
Basically all standard collections supports this way of iteration.
It's called a forin loop, also called fast enumeration. Basically, the syntax is:
for (SomeObjectIAmExpecting *localVariableName in anArrayOfObjects)
{
if (![localVariableName isKindOfClass:[SomeObjectIAmExpecting class]]) continue; //To avoid errors.
//do something to them
}
Huge proponent of using the 'var' keyword in C# for cases where it's very clear. For instance, rather than this...
ThisIsMyReallyLongFooClassName foo = new ThisIsMyReallyLongFooClassName();
I can type this...
var foo = new ThisIsMyReallyLongFooClassName();
...and I still have a strongly-typed variable. The two are, for all intents and purposes, equal. The latter is just more readable (again, because it's clear. There are cases where it isn't and 'var' shouldn't be used. I don't want this to become a discussion of that however.)
I'm wondering if Objective-C has anything similar.
Yes and no.
You can use id foo = ... which will always work, but you lose the type information.
If you really want something equivalent, you could use auto foo = ... from C++11, but then you have to compile your file as Objective-C++, which has many other side effects.
Convention is to just spell out your types; it's annoying, but unlike C++, C#, Java where templates/generics can make typenames very long, it's usually manageable in Objective-C.
There is now, __auto_type. For example...
__auto_type test = #"Hello World";
...results in test having the type NSString*.
Here's a decent writeup:
https://medium.com/#maicki/type-inference-with-auto-type-55a38ef56372
The author suggests using
#define let __auto_type const
#define var __auto_type
in some shared header in your application to make the usage cleaner. I'm a bit wary of this kind of macro usage personally but I've been doing it for a while and the world is still turning... Maybe macro names less likely to cause a collision would be better.
No, there is no equivalent in Objective C. C++11 introduced the auto keyword to do it, but neither C nor Objective C has a similar capability.
The id is closest to C#'s dynamic keyword. It lets you achieve similar results to var, except that it does not let you access properties using the property syntax. It does let you invoke methods, including methods that implement property accessors.
You can do something like this:
__typeof([obj someMethod]) foo = [obj someMethod];
That's ugly, but if you have a snippet or macro defined to automatically generate it, then you don't have to type out the type names. For example:
#define LET(V, EXPR) __typeof(EXPR) V = (EXPR)
LET(vc, self.viewController); // equivalent to "UIViewController* vc = self.viewController;"
LET(d, [number doubleValue]); // equivalent to "double d = [number doubleValue];"
LET(foo, [[Foo alloc] init]); // equivalent to "Foo *foo = [[Foo alloc] init];"
Note: I'm not recommending this approach, as the convention in Objective-C is to write out the full type names or use id, and macros can be messy. But knowing about __typeof() can be handy.
There is the id keyword in Objective-C, but note that it is equivalent to the dynamic keyword in C# and not the var keyword. var is implicit typing - ie the type is inferred, but it is still static typing. dynamic and id are for dynamic typing and you lose type information.
I am afraid that no such equivalent exists in Objective C which would allow you to preserve strong typing.
You can use id keyword in objective C, but it doesn't work as c#
in c#
var stringVar = ...
stringVar worked as string variable and you can use access the string function by doing stringVar.function
id stringVar = [NSString ...]
but it still work as normal id type.
I have seen this question and its answers and they clear up some of my confusion, but I'm still concerned about a couple things:
Consider this:
int someCArray[5]={1,2,3,4,5};
[self processingTheArray:someCArray];
The method is described as:
-(void)processingTheArray:(int)theCArray;
Now, the above works, even though I gather it is not the right way to do it. It does provide a compiler warning: Incompatible pointer to integer conversion. Need I be concerned since this is working anyway?
Using the method in the above linked SO question, I could do this:
-(void)processingTheArray:(int)theCArray size:(NSUInteger)length;
However, what do I do with length inside processingTheArray?
someCArray is of type int*, not Byte*. int and Byte are different sizes, and are incompatible.
By changing your method to -(void)processingTheArray:(int*)theCArray;, it will work without warning.
However, the method takes your array in as a pointer, and it does not know if theCArray includes one int, 5 ints, or 500 ints inside. Unless the array is always the exact same length, you want a length parameter to specify the array size, so inside the method, you can loop or do whatever you want.
You could have something like:
for (int i = 0; i < length; i++) {
theCArray[i]; // do something
}
inside of your processingTheArray: function.
Occasionally, during development/debugging, I want to ensure that an object is of a certain type:
PageTopBottom *newPage = [notification object];
assert([newPage isKindOfClass:[PageTopBottom class]]);
which I've worked into this
#define assertType(_var_, _class_) assert([_var_ isKindOfClass:[_class_ class]])
and
PageTopBottom *newPage = (id)[notification object];
assertType(newPage, PageTopBottom);
but now I'd like to, if possible, just use
assertType(newPage)
Is it possible to get information about a variable's declared type from the variable?
I'm not positive that I'm framing the question correctly, but any answer that gets me to be able to assertType with one parameter would be great.
Is it possible to get information about a variable's declared type from the variable?
No. By the time the program is running, that information is lost. In your case, newPage is just a 32 or 64 bit number that points to a bit of memory that holds an Objective-C object.
I think your original unmacro'd version is the right thing to do here:
assert([newPage isKindOfClass:[PageTopBottom class]]);
That perfectly documents the assumption you are making i.e. that you assume newPage is an instance of PageTopBottom or one of its subclasses and it's completely clear to anybody who understands Objective-C. Your macro version slightly obfuscates that, in that somebody coming across it in the code might beleive it is asserting that newPage is a PageTopBottom and not one of its subclasses (you could change the name of the macro to prevent that, I suppose, but I just wouldn't bother).
Edit
What you could do is combine the declaration and assertion in one:
#define DECLARE_AND_ASSERT_IS_KIND_OF_CLASS(T, V, I) T* V = (T*)(I); assert([(V) isKindOfClass: [(T) class])
which would work like this:
DECLARE_AND_ASSERT_IS_KIND_OF_CLASS(PageTopBottom, newPage, [notification object]);
Hmm, with Objective-C++ there are two options:
Write a template function
template void assertType(T* obj) { ... }
For a pointer X* x, use NSClassFromString([NSString stringWithUTF8String:typeid(*x).name()]).
Without using C++, you might be able to use GCC extension typeof, but I'm not sure if [typeof(*x) class] is a legit operation...
The preprocessor only processes text; it has no knowledge of type, which is why it's sometimes considered 'dangerous'. The only way I could see doing it is wrapping the variable declarations in a macro, which I would strongly advise against, and probably wouldn't actually cut down on the code or complexity.
Also, shouldn't you check the type before casting?