When making a small open source iOS API, how do I account for ARC and non-arc users - iphone

I have seen some libraries use separate branches in their source control. One for ARC one for non-ARC. I dont see this as partical as it requires extra maintaince.
A method I thought was to use the compiler flag: (see this question)
#if __has_feature(objc_arc)
Whenever I need to use retain release etc... That way if the user has it switched on the code will automatically re-factor itself.
Is there a disadvantage of doing this way?
Is there a better way to do it?

While Dave's answer is correct, there is an alternative pattern that avoids having to maintain two memory models in your code.
Namely, compile your code with ARC required and either:
use a static library to distrubute your code; whether that static library is built by a new target in the destination project or you distribute the library itself, ARC can be turned on for the target that builds the library.
turn on ARC for just the files when added to whatever target in the target project. ARC can be turned on per-file.
In any case, mixing ARC and non-ARC code at the per-file level is fully supported and works just fine (as demonstrated by the fact that the system frameworks are almost entirely compiled non-ARC, but work fine from ARC).

That's pretty much how I do it. I also have some macros so that my code stays relatively "clean":
#if __has_feature(objc_arc)
#define DD_HAS_ARC 1
#define DD_RETAIN(_o) (_o)
#define DD_RELEASE(_o)
#define DD_AUTORELEASE(_o) (_o)
#else
#define DD_HAS_ARC 0
#define DD_RETAIN(_o) [(_o) retain]
#define DD_RELEASE(_o) [(_o) release]
#define DD_AUTORELEASE(_o) [(_o) autorelease]
#endif
With these, I can do stuff like:
return DD_AUTORELEASE(DD_RETAIN(_myIvar));
Or:
DD_RELEASE(_myIvar);
_myIvar = DD_RETAIN(newObject);
Or:
- (void)dealloc {
DD_RELEASE(_myIvar);
#if !DD_HAS_ARC
[super dealloc];
#endif
}
And then the macro expands into the correct code depending on whether I'm compiling with ARC or not.

If you are developing a static (compiled) library then you can use what ever approach you want.
Most of the difference is at compile time.
Meaning that the generated output should be the same (if you manage the memory properly in the non-ARC version).
Once you compile it, any project may use it without concerning whether your library was developed with or without ARC.
Bottom line, you may develop an ARC based library and use it in non-ARC project (and visa versa) with no problem.

Related

What does this mean? #if !(arch(x86_64) || arch(arm64))

I came across this unusual code in a tutorial I was using.
#if !(arch(x86_64) || arch(arm64))
func sqrt(a: CGFloat) -> CGFloat {
return CGFloat(sqrtf(Float(a)))
}
#endif
It looks nothing like the code I've been learning so far. I know it's a square root function but the hashtag? Something about my computer architecture?
Please explain it to me in simple terms.
#if condition
// Code in here
#endif
This is a conditional compilation directive - it is used to hide blocks of code from the compiler. The code in the block is only compiled if the condition is true.
It's supported in many languages, notably C and C++. It is often used to account for processor architecture and operating system differences - allowing one code-base to compile on many different platforms.
It can also be used to remove debugging/tracing code in a release build.
The condition is evaluated once at compile time, normally in an initial pass over the source code before the main compiler.
You can set those kind of conditional compilation directive for various purpose.
For example you might have an environnement for DEBUG and one for RELEASE, depending on which you wan't to compile your might not use the same functions / values.
In you case, #if !(arch(x86_64) || arch(arm64)) is to determine the architecture of your device (or simulator).
Indeed, some iDevice run 32bits and others 64bits (5S and newer). Float aren't represented the same way.
As #Martin wrote, you might not have to use this code anymore :)

Pre-processor macros in xcconfig files

is is possible to use macros in config files? I want to achieve something like:
if iPad
set variable to 1
else
set variable to 0
Is that possible? I would rather not use scripts for this.
You generally should check this at runtime rather than compile time. See iOS - conditional compilation (xcode).
If you don't do it that way, I typically recommend using different targets as hinted at by #Robert Vojta.
That said, I can imagine cases where this would be useful in some piece of shared code. So...
There is an xcconfig variable you can use called TARGETED_DEVICE_FAMILY. It returns 1 for iPhone and iPod Touch, and 2 for iPad. This can be used to create a kind of macro. I don't highly recommend this approach, but here's how you do it. Let's say you were trying to set some value called SETTINGS:
// Family 1 is iPhone/iPod Touch. Family 2 is iPad
SettingsForFamily1 = ...
SettingsForFamily2 = ...
SETTINGS = $(SettingsForFamily$(TARGETED_DEVICE_FAMILY))
I've done this a few times in my projects (for other problems, not for iPad detection). Every time I've done it, a little more thought has allowed me to remove it and do it a simpler way (usually finding another way to structure my project to remove the need). But this is a technique for creating conditionals in xcconfig.
AFAIK it's not possible. But if you want to solve simple task - lot of common settings and just few variables have different values, you can do this:
generic.xcconfig:
settings for both configs
ipad.xcconfig:
#include "generic.xcconfig"
ipad-specific-settings
iphone.xcconfig
#include "generic.xcconfig"
iphone-specific-settings
This can solve your condition need. I do use this schema frequently.
That's not possible. Configuration files are not preprocessed (and compiled). What are you trying to do?

Disabling NSLogs from .a libs

I've a lot of .a in my project from various libraries and some of the spam the console with
output.
Is there a way to disable all NSLogs from my build even my own?
Will these effect the final release build in anyway?
For example:
AD URL: http://ads.mp.mydas.mobi/getAd.php5?medialets=false&sdkapid=44300&auid=a83014b158258e5bda3ee3f3634eaa17b66d9fce&mmisdk=4.2.4-11.4.25.i&ua=iPhone%204.2.1&dv=4.2.1&dm=iPhone2,1&adtype=MMBannerAdTop&hswd=320&hsht=53&accelerometer=true&vendor=adwhirl&video=true&language=en&country=IE&cachedvideo=true
This gets output to the console. But searching in the project for text 'AD URL' finds nothing. Can I force these to be removed ignored somehow?
NSLog does indeed effect the performance of release builds. I recommend doing a global search and replace of all NSLog statements. That way, you can delete or at least comment out all logging statements.
For future reference, you can make your own loggig function that wraps NSLog, but checks for a compile time constant, which you would define.
EDIT:
It might be possible to override those NSLogs with a category. (I have no clue which class to make a category of, however.)
simple (but not the cleanest of approaches) approach is to declare some #define like
#if defined(NO_LOGS)
#define NSLog(xyz)
#endif
which will supress all NSLog statements when you turn on NO_LOGS.

How to include code into the build only when a flag is set?

I have added some debugging code to my app which I want to call only when needed. I remember there is some kind of IFDEF that can be used to conditionally include code into a source file.
For example I might have something like this:
IFDEF kDebugEnabled == YES {
// some debugging code here
}
And then this piece of code is only compiled into the binary if that kDebugEnabled is YES.
How can I do something like this?
Please note: I don't want to use the project compiler flag settings. I just want to define a BOOL (or something that serves the purpose just as well) which is true or false and then just easily set it in my App Delegate for example. I find it hard to navigate to the project compiler settings, searching for a flag and then setting it. I know there is a Debug flag which might be of use.
What you are looking for is:
#ifdef __YOURSYMBOL__
<conditional code>
#endif
You can programmatically define __YOURSYMBOL__ like this:
#define __YOURSYMBOL__
__YOURSYMBOL__ can be any string that makes sense to you to remember why you are including/excluding that code snippet.
The DEBUG constant is a special preprocessor constant that the compiler defines specifically for you when the code is built for debugging, so you can simply use it:
#ifdef DEBUG
<conditional code>
#endif
Take into account that this is the C-preprocessor, not C, nor Objective-C that you are using, so a test like kDebugEnabled == YES (where kDebugEnabled is an Objective-C variable) is simply not possible. You can define integer values for your constants, like this:
#define __LOG_LEVEL__ 3
and then test for it:
#if __LOG_LEVEL__ == 3
...
Endif
As far as I know, you can't have code in your classes that is not compiled into the final product without using compiler flags. However, using the DEBUG flag is a lot easier than you think. If you are using Xcode 4, it's set up for you by default.
#ifdef DEBUG
// Your debug-only code goes here
#endif // DEBUG
Xcode has, by default, two configurations, Debug and Release. When you use the debug build configuration, among other things, it sets the DEBUG compiler flag, which you can then use to conditionally compile code. No need to mess with compilation settings at all.

Getting started reverse-engineering OS X?

What is a good place to learn reverse engineering, specifically as it applies to Mac OS X? Two apps that I admire in terms of this subject:
Hyperspaces – Link
and
Orbit – http://www.steventroughtonsmith.com/orbit/
Thanks guys.
You should grab a copy of Mac OS X Internals which is an awesome book about everything that Apple does not tell you. Not only is this great if you are interested in reverse engineering, it will also make you a better OS X programmer in general.
Use class-dump-x/-z to get the private Objective-C headers for OS X/iPhone OS system frameworks. There are a lot of classes/methods hidden from the public (some rightly so)
Apple releases a ton of the foundation of OS X as open source. See here.
In addition, F-Script Anywhere will help a ton with dissecting the Finder and/or any other closed source application.
For iPhoneOS specifically, class-dump-z is a great way to dump headers. The only problem, of course, is that you can't actually see what is going on inside of each method. IDA Pro and a few scripts make it possible to see the assembly instructions for these system frameworks. (example picture: http://grab.by/1Vn6).
The most handy IDC scripts are fixobjc2 and dyldinfo. You can find each of these linked from this blog post: http://networkpx.blogspot.com/2010/01/two-ida-pro-5x-scripts-for-iphoneos.html
But, what good is this information if you can't use it? iPhone developer saurik has written something called MobileSubstrate that enables hooking onto any method. http://svn.saurik.com/repos/menes/trunk/mobilesubstrate/
Others have already mentioned class-dump, which is an excellent tool for retrieving the class definitions from a compiled executable. On a related note, you should also take a look at otx, which is provides very nice (readable), disassembled output.
If you need a way to quickly test snippets of code, use F-Script (mentioned by others), Nu or MacRuby. Of these, I've mainly used Nu. It has the capability to define bridged functions on the fly, and can handle pointers, both of which are pretty handy if you need to call arbitrary C functions.
Since you mentioned being interesting in Spaces and other screen managers, you should also read A brief tutorial on reverse engineering OS X. It's an old article by Rich Wareham (author of the pre-Spaces multi-desktop app: 'Desktop Manager') on how he figured out the call syntax for few private CoreGraphics methods in order to do nice desktop transitions. The source code for Desktop Manager is also available, which might be useful to you.
This site shows how to patch an existing Objective C program: http://www.culater.net/wiki/moin.cgi/CocoaReverseEngineering
Namely posing:
[[B class] poseAsClass:[A class]];
and method swizzling:
/**
* Renames the selector for a given method.
* Searches for a method with _oldSelector and reassigned _newSelector to that
* implementation.
* #return NO on an error and the methods were not swizzled
*/
BOOL DTRenameSelector(Class _class, SEL _oldSelector, SEL _newSelector)
{
Method method = nil;
// First, look for the methods
method = class_getInstanceMethod(_class, _oldSelector);
if (method == nil)
return NO;
method->method_name = _newSelector;
return YES;
}
// *** Example ***
// never implemented, just here to silence a compiler warning
#interface WebInternalImage (PHWebInternalImageSwizzle)
- (void) _webkit_scheduleFrame;
#end
#implementation WebInternalImage (PHWebInternalImage)
+ (void) initialize
{
DTRenameSelector([self class], #selector(scheduleFrame), #selector (_webkit_scheduleFrame));
DTRenameSelector([self class], #selector(_ph_scheduleFrame), #selector(scheduleFrame));
}
- (void) _ph_scheduleFrame
{
// do something crazy...
...
// call the "super" method - this method doesn't exist until runtime
[self _webkit_scheduleFrame];
}
#end
(code copied from http://www.culater.net/wiki/moin.cgi/CocoaReverseEngineering)
As an addition to the other answers, you are going to want to check out DYLD_INSERT_LIBRARIES to inject your code into a Cocoa program.
You should definitely consider using DTrace. There is an excellent BlackHat presentation on using DTrace for reverse engineering on OS X entitled, "DTRACE: The Reverse Engineer's Unexpected Swiss Army Knife".
You can get a copy and view the video presentation here.
There are also some excellent papers at www.uninformed.org on reverse engineering OS X.