Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

372 lines (311 sloc) 16.289 kb
// Copyright 1997-2014 Omni Development, Inc. All rights reserved.
// This software may only be used and reproduced according to the
// terms in the file OmniSourceLicense.html, which should be
// distributed with this project and can also be found at
// <>.
// $Id$
#import <Foundation/NSString.h>
#import <Foundation/NSBundle.h>
#import <Foundation/NSDate.h>
#import <CoreGraphics/CGGeometry.h>
#import <UIKit/UIGeometry.h>
#import <Foundation/NSGeometry.h> // For NSGEOMETRY_TYPES_SAME_AS_CGGEOMETRY_TYPES
#import <OmniBase/assertions.h>
#import <OmniBase/objc.h>
#import <OmniBase/macros.h>
#if defined(__cplusplus)
extern "C" {
#if defined(__GNUC__)
#define NORETURN __attribute__ ((noreturn))
#define NORETURN
#define OB_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
// In some cases, we really need to keep an object alive. For example, we may have a window controller that will release itself in response to its window being closed.
static inline void OBStrongRetain(id object)
if (object) {
void *ptr = (OB_BRIDGE void *)object;
static inline void OBStrongRelease(id object)
if (object) {
void *ptr = (OB_BRIDGE void *)object;
static inline void OBAutorelease(id object)
if (object) {
void *ptr = (OB_BRIDGE void *)object;
static inline void OBRetainAutorelease(id object)
// NSAllocateObject and object_getIndexedIvars are not availabe in ARC. Uses of these should be rare...
extern id OBAllocateObjectWithIndexedIvars(Class cls, size_t indexedIvarsSize) NS_RETURNS_RETAINED;
extern void *OBObjectGetIndexedIvars(id object);
// ARC doesn't allow object_getInstanceVariable().
extern void OBObjectGetUnsafeObjectIvar(id object, const char *ivarName, __unsafe_unretained id *outValue);
// ARC doesn't allow casting between 'void **' and '__unsafe_unretained id *' for some reason.
extern __unsafe_unretained id *OBCastMemoryBufferToUnsafeObjectArray(void *buffer);
// iOS 8 adds frameworks/bundles.
#define OMNI_BUNDLE [NSBundle mainBundle]
// This uses the OMNI_BUNDLE_IDENTIFIER compiler define set by the OmniGroup/Configurations/*Global*.xcconfig to look up the bundle for the calling code.
static inline NSBundle *_OBBundleWithIdentifier(NSString *identifier)
OBPRECONDITION([identifier length] > 0); // Did you forget to set OMNI_BUNDLE_IDENTIFIER in your target?
NSBundle *bundle = [NSBundle bundleWithIdentifier:identifier];
OBPOSTCONDITION(bundle); // Did you set it to the wrong thing?
return bundle;
extern void _OBRequestConcreteImplementation(id self, SEL _cmd, const char *file, unsigned int line) NORETURN;
extern void _OBRejectUnusedImplementation(id self, SEL _cmd, const char *file, unsigned int line) NORETURN;
extern void _OBRejectInvalidCall(id self, SEL _cmd, const char *file, unsigned int line, NSString *format, ...)
NORETURN __attribute__((format(__NSString__, 5, 6)));
#define OBRequestConcreteImplementation(self, sel) _OBRequestConcreteImplementation((self), (sel), __FILE__, __LINE__)
#define OBRejectUnusedImplementation(self, sel) _OBRejectUnusedImplementation((self), (sel), __FILE__, __LINE__)
#define OBRejectInvalidCall(self, sel, format, ...) _OBRejectInvalidCall((self), (sel), __FILE__, __LINE__, (format), ## __VA_ARGS__)
// A common pattern when refactoring or updating code is to #if 0 out portions that haven't been updated and leave a marker there. This function serves as the 'to do' marker and allows you to demand-port the remaining code after working out the general structure.
// NOTE: The formatting of the "header" argument is formulated so you can run 'strings' on your binary and find a list of all the file:line locations of these.
extern void _OBFinishPorting(const char *header, const char *function) NORETURN;
#define _OBFinishPorting_(file, line, function) _OBFinishPorting("OBFinishPorting at " file ":" #line, function)
#define _OBFinishPorting__(file, line, function) _OBFinishPorting_(file, line, function)
#define OBFinishPorting _OBFinishPorting__(__FILE__, __LINE__, __PRETTY_FUNCTION__)
// Something that needs porting, but not immediately
extern void _OBFinishPortingLater(const char *header, const char *function, const char *message);
#define _OBFinishPortingLater_(file, line, function, message) _OBFinishPortingLater("OBFinishPortingLater at " file ":" #line, function, (message))
#define _OBFinishPortingLater__(file, line, function, message) _OBFinishPortingLater_(file, line, function, (message))
#define OBFinishPortingLater(msg) do { \
static BOOL warned = NO; \
if (!warned) { \
warned = YES; \
_OBFinishPortingLater__(__FILE__, __LINE__, __PRETTY_FUNCTION__, (msg)); \
} \
} while(0)
extern BOOL OBIsBeingDebugged(void);
extern void _OBStopInDebugger(const char *file, unsigned int line, const char *function, const char *message);
#define OBStopInDebugger(message) _OBStopInDebugger(__FILE__, __LINE__, __PRETTY_FUNCTION__, (message))
#define OBStepThroughAndVerify() _OBStopInDebugger(__FILE__, __LINE__, __PRETTY_FUNCTION__, "Step through and verify.")
extern NSString * const OBAbstractImplementation;
extern NSString * const OBUnusedImplementation;
#if defined(DEBUG)
#define OB_DEBUG_LOG_CALLER() do { NSArray *syms = [NSThread callStackSymbols]; if ([syms count] > 1) NSLog(@"caller: %@", [syms objectAtIndex:1U]); } while (0)
enum OBBacktraceBufferType {
OBBacktraceBuffer_Unused = 0, /* Indicates an unused slot */
OBBacktraceBuffer_Allocated = 1, /* Allocated but not filled slot */
/* Remaining integers represent different reasons for recording a backtrace */
OBBacktraceBuffer_OBAssertionFailure = 2,
OBBacktraceBuffer_NSAssertionFailure = 3,
OBBacktraceBuffer_NSException = 4,
void OBRecordBacktrace(const char *ctxt, unsigned int optype);
Records a backtrace for possible debugging use in the future. ctxt and optype are free for the caller to use for their own purposes, but optype must be greater than one.
extern IMP OBRegisterInstanceMethodWithSelector(Class aClass, SEL oldSelector, SEL newSelector);
Provides the same functionality as +[NSObject registerInstanceMethod:withMethodTypes:forSelector: but does it without provoking +initialize on the target class. Returns the original implementation.
extern IMP OBReplaceMethodImplementation(Class aClass, SEL oldSelector, IMP newImp);
Replaces the given method implementation in place. Returns the old implementation.
IMP OBReplaceMethodImplementationFromMethod(Class aClass, SEL oldSelector, Method newMethod);
Replaces the given method implementation in place. Returns the old implementation.
extern IMP OBReplaceMethodImplementationWithSelector(Class aClass, SEL oldSelector, SEL newSelector);
Calls the above, but determines newImp by looking up the instance method for newSelector. Returns the old implementation.
extern IMP OBReplaceMethodImplementationWithSelectorOnClass(Class destClass, SEL oldSelector, Class sourceClass, SEL newSelector);
Calls OBReplaceMethodImplementation. Derives newImp from newSelector on sourceClass and changes method implementation for oldSelector on destClass.
extern IMP OBReplaceClassMethodImplementationWithSelector(Class aClass, SEL oldSelector, SEL newSelector);
Calls OBReplaceMethodImplementationWithSelector with aClass's metaclass as the class argument. aClass must not itself be a metaclass.
extern IMP OBReplaceClassMethodImplementationFromMethod(Class aClass, SEL oldSelector, Method newMethod);
Calls OBReplaceMethodImplementationFromMethod with aClass's metaclass as the class argument. aClass must not itself be a metaclass.
extern Class OBClassImplementingMethod(Class cls, SEL sel);
// This returns YES if the given pointer is a class object
static inline BOOL OBPointerIsClass(id object)
if (object) {
Class cls = object_getClass(object);
return class_isMetaClass(cls);
return NO;
// This returns the class object for the given pointer. For an instance, that means getting the class. But for a class object, that means returning the pointer itself
static inline Class OBClassForPointer(id object)
if (!object)
return object;
if (OBPointerIsClass(object))
return object;
return object_getClass(object);
static inline BOOL OBClassIsSubclassOfClass(Class subClass, Class superClass)
while (subClass) {
if (subClass == superClass)
return YES;
subClass = class_getSuperclass(subClass);
return NO;
extern NSString *OBShortObjectDescription(id anObject);
extern NSString *OBShortObjectDescriptionWith(id anObject, NSString *extra);
extern NSString *OBFormatObjectDescription(id anObject, NSString *fmt, ...)
__attribute__((format(__NSString__, 2, 3)));
extern CFStringRef const OBBuildByCompilerVersion;
// This macro ensures that we call [super initialize] in our +initialize (since this behavior is necessary for some classes in Cocoa), but it keeps custom class initialization from executing more than once.
do { \
static BOOL hasBeenInitialized = NO; \
[super initialize]; \
if (hasBeenInitialized) \
return; \
hasBeenInitialized = YES;\
} while (0);
// Sometimes a value is computed but not expected to be used and we wish to avoid clang dead store warnings. For example, when laying out a stack of views, we might keep a running total of the used height and might want to do this for the last item stacked up (in case something is added later).
// Using overloadable functions here lets us handle object types (since we can't cast those to void * w/o __bridge and we can't cast non object types to void * _with_ __bridge).
static inline void __attribute__((overloadable)) _OBUnusedValue(id v) {
__strong id *__ptr __attribute__((unused)) = &v; /* ensure it is actually an l-value */ \
typeof(v) __unused_value __attribute__((unused)) = v;
static inline void __attribute__((overloadable)) _OBUnusedValue(T v) { \
void *__ptr __attribute__((unused)) = (void *)&v; /* ensure it is actually an l-value */ \
typeof(v) __unused_value __attribute__((unused)) = v; \
#define OB_UNUSED_VALUE(v) _OBUnusedValue(v)
// Versions of cpp-precomp released before April 2002 have a bug that makes us have to do this
#define NSSTRINGIFY(name) @ ## '"' ## name ## '"'
#elif defined(__GNUC__)
#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3)
// GCC before 3.3 requires this format
#define NSSTRINGIFY(name) @ ## #name
// GCC 3.3 requires this format
#define NSSTRINGIFY(name) @#name
// An easy way to define string constants. For example, "NSSTRINGIFY(foo)" produces @"foo" and "DEFINE_NSSTRING(foo);" produces: NSString *foo = @"foo";
#define DEFINE_NSSTRING(name) \
NSString * const name = NSSTRINGIFY(name)
// Iterators over C arrays and literals. Useful for iterating over collections known at compile-time, like when (un)registering KVO keypaths. Syntax is similar to a regular for(.. in ..) statement; the first argument is a variable name that is visible within the scope of the block controlled by the OB_FOR_ALL or OB_FOR_IN statement. The subsequent arguments vary.
// Helper macro that drives iteration of the variable named by OB_FOR_var_name over the array named by OB_FOR_array_name.
#define OB_FOR_exprs(OB_FOR_var_name, OB_FOR_array_name) \
*OB_FOR_IN_end = &OB_FOR_array_name[sizeof(OB_FOR_array_name)/sizeof(OB_FOR_array_name[0])], /* Points one past the end of the array */ \
*OB_FOR_IN_curr = &OB_FOR_array_name[0], \
OB_FOR_var_name = OB_FOR_array_name[0]; \
OB_FOR_IN_curr < OB_FOR_IN_end ? (OB_FOR_var_name = *OB_FOR_IN_curr, 1) : 0; /* Avoid dereferencing pointer one past the end of the array, even if we never use it */ \
// OB_FOR_ALL takes a variable number of arguments (at least two) and iterates over all of them.
// Ex:
// OB_FOR_ALL(i, 1, 2, 3)
// printf("%d", i);
#define OB_FOR_ALL(var, one, ...) for(typeof(one) OB_FOR_ALL_array[] = { one, __VA_ARGS__ }, OB_FOR_exprs(var, OB_FOR_ALL_array))
// OB_FOR_IN takes a single array variable as an argument and iterates over its members.
// Ex:
// int nums[] = {1, 2, 3};
// OB_FOR_IN(i, nums)
// printf("%d", i);
#define OB_FOR_IN(var, array) for (typeof(array[0]) OB_FOR_exprs(var, array))
// Emits a warning indicating that an obsolete method has been called.
do { \
static BOOL warned = NO; \
if (!warned) { \
warned = YES; \
NSLog(@"Warning: obsolete method %c[%@ %@] invoked", OBPointerIsClass(self)?'+':'-', OBClassForPointer(self), NSStringFromSelector(_cmd)); \
} \
OBASSERT_NOT_REACHED("obsolete method called"); \
} while(0)
// Apple doesn't have an NSNotFound equivalent for NSUInteger values (NSNotFound is an NSInteger).
// Note that for APIs which should match Foundation APIs, you'll need to use NSNotFound even for NSUInteger values.
#define OB_NSUInteger_NotFound (~(NSUInteger)0)
// Returns a copy of the method signature with the NSGeometry types replaced with CG types. The result should be free'd by the caller.
__attribute__((visibility("hidden"))) const char *_OBGeometryAdjustedSignature(const char *sig);
// Inttypes-style format macros for Apple-defined types
// On these platforms NSInteger=long and NSUInteger=unsigned long
#define PRI_NSInteger_LENGTH_MODIFIER "l"
// On these platforms NSInteger=int and NSUInteger=unsigned int
#define PRI_NSInteger_LENGTH_MODIFIER ""
// OSStatus is SInt32, which is int on 64-bit and long on 32-bit. Similar problems hit CFStringEncoding and UnicodeScalarValue
// note this is unaffected by NS_BUILD_32_LIKE_64, etc.
#if __LP64__
// On these platforms, UInt32 and SInt32 are (unsigned) int, and therefore so is OSStatus
#define PRI_OSStatus "d"
#define PRI_CFStringEncoding "u"
#define PRI_UnicodeScalarValue "u"
// On these platforms, UInt32 and SInt32 are (unsigned) long, and therefore so is OSStatus
#define PRI_OSStatus "ld"
#define PRI_CFStringEncoding "lu"
#define PRI_UnicodeScalarValue "lu"
// ptrdiff_t
#define PRI_ptrdiff "td"
/* CFIndex is always a signed long as far as I know */
#define PRIdCFIndex "ld"
#if defined(__cplusplus)
} // extern "C"
Jump to Line
Something went wrong with that request. Please try again.