Skip to content

Instantly share code, notes, and snippets.

@karstenBriksoft
Last active December 20, 2020 08:08
Show Gist options
  • Save karstenBriksoft/8e2f4c2bcda0a790ead36f89f8e03b88 to your computer and use it in GitHub Desktop.
Save karstenBriksoft/8e2f4c2bcda0a790ead36f89f8e03b88 to your computer and use it in GitHub Desktop.
//
// TCObject.m
//
//
// Created by Karsten Kusche on 19.12.20.
// Copyright © 2020 briksoftware.com. All rights reserved.
//
//
// compile with -fno-objc-arc
//
// This code changes +alloc so that it initializes all inst-vars that have the type <id> to not be <nil> but [TCNull null]
// TCNull prints a Stack-Dump when a message is sent to it, that it doesn't understand. <nil> would silently return nil
// <nil> receivers are typically an indication of missing initialization and the error manifests a lot later
// with this fix it'll crash as soon as someone sends a message to an uninitialized variable
//
// don't use in production code, but during development it's sure helpful
//
#import "TCObject.h"
#import <objc/objc-runtime.h>
@interface TCNull : NSObject
+ (instancetype)null;
@end
Method orgAlloc = nil;
@implementation TCObject
+ (instancetype)tcAlloc
{
// only handle TC* classes. System classes don't play well with this idea
const char* name = class_getName(self);
if (name[0] == 'T' && name[1] == 'C')
{
IMP alloc = method_getImplementation(orgAlloc);
SEL allocSel = method_getName(orgAlloc);
TCObject* object = ((id(*)(id,SEL))alloc)(self,allocSel);
unsigned int outCount = 0;
Ivar* ivars = class_copyIvarList(self, &outCount);
for (NSInteger i = 0; i < outCount; i++)
{
Ivar ivar = ivars[i];
const char* type = ivar_getTypeEncoding(ivar);
if (*type == '@')
{
object_setIvar(object, ivar, [TCNull null]);
}
}
free(ivars);
return object;
}
else
{
IMP alloc = method_getImplementation(orgAlloc);
SEL allocSel = method_getName(orgAlloc);
return ((id(*)(id,SEL))alloc)(self,allocSel);
}
}
+ (void)load
{
@autoreleasepool {
[TCNull null];
[self swizzle];
}
}
+ (void)swizzle
{
Method alloc = class_getClassMethod(NSObject.class, @selector(alloc));
Method tcAlloc = class_getClassMethod(self, @selector(tcAlloc));
orgAlloc = tcAlloc;
method_exchangeImplementations(alloc, tcAlloc);
}
@end
@implementation TCNull
+ (instancetype)null
{
static TCNull* null = nil;
if (null == nil)
{
null = [[self alloc] init];
}
return null;
}
- (void)doesNotRecognizeSelector:(SEL)aSelector
{
raise(SIGINT);
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment