How to write a macro wrapper for a method in Objective-C++ - objective-c++

I have a lot of this in my work codebase:
__typeof(self) __weak weakSelf = self;
dispatch_async(_queue, ^{
auto strongSelf = weakSelf;
if (!strongSelf) {
return;
}
[strongSelf doSomething:aParam paramB:paramB];
});
I'd like to replace all the boilerplate with a macro. Something like:
#define RUN_SAFELY_ON_QUEUE(q_, METHOD) \
__typeof(self) __weak weakSelf = self; \
dispatch_async(q_, ^{ \
auto strongSelf = weakSelf; \
if (!strongSelf) { \
return; \
} \
METHOD() \
}); \
And then run things like:
RUN_SAFELY_ON_QUEUE(_queue, [self doSomething:aParam paramB:paramB]);
Currently, I'm getting the error: "Called object type 'void' is not a function or function pointer".
Is what I'm looking for possible?
Thanks for the help!

This works, and make sure to add () around the param:
#define RUN_SAFELY(q_, METHOD) \
__weak __typeof(self) weakSelf = self; \
dispatch_async((q_), ^{ \
auto strongSelf = weakSelf; \
if (!strongSelf) { \
return; \
} \
(METHOD); \
}); \
And use it like so:
RUN_SAFELY(dispatch_get_main_queue(), [self doSomething:aParam paramB:paramB]);

Related

Detect Missing JSON Keys With Nested Objects

Currently I am in the process of working with an API that is still in development. Due to this, the keys in the response are still changing. I have successfully been able to retrieve and parse the JSON data from the API into an NSDictionary, and then use this NSDictionary to map the values into custom objects. The approach I am using is the following
-(id)initWithDictionary:(NSDictionary*)dictionary
{
if(self = [super init]){
_ID = [dictionary valueForKey:kKEY_ID];
_name = [dictionary valueForKey:kKEY_NAME];
_nestedObject = [[NestedObject alloc]initWithDictionary:[dictionary valueForKey:kKEY_NESTED_OBJECT]];
//etc...
}
return self
}
Each nested object also contains the same parsing structure.
This works fine except for when the API changes. When something does change, required values do not exist and this causes unexpected behavior or crashes.
Ideally, if one of the keys change, I would like to produce a NSError that I can use to print the value that has changed helping me more quickly find the change and rectify it.
The only alternative approach that I have currently been able to come up with I feel is messy and unmaintainable.
-(id)initWithDictionary:(NSDictionary*)dictionary andError:(NSError**)error
{
if(self = [super init]){
BOOL _parsedSuccessfully = TRUE;
if (_parsedSuccessfully) {
_ID = [dictionary valueForKey: kKEY_ID];
if (!_ID){
_parsedSuccessfully = FALSE;
*error = [NSError parsingErrorFromKey: kKEY_ID];
}
}
if (_parsedSuccessfully) {
_name = [dictionary valueForKey: kKEY_NAME];
if (!_name){
_parsedSuccessfully = FALSE;
*error = [NSError parsingErrorFromKey: kKEY_NAME];
}
}
if (_parsedSuccessfully) {
_nestedObject = [[NestedObject alloc]initWithDictionary:[dictionary valueForKey:kKEY_NESTED_OBJECT]];
if (!_nestedObject){
_parsedSuccessfully = FALSE;
*error = [NSError parsingErrorFromKey: kKEY_NESTED_OBJECT];
}
}
//etc...
if (!_parsedSuccessfully) {
return nil;
}
}
return self
}
I was wondering if anyone else had any other better approaches that preferably uses much less duplication.
Any help would be greatly appreciated.
Add an isValid method to your object, which can be used in any situation, not just when initialised from the JSON dictionary.
- (BOOL)isValid:(NSError **)error {
#define CHECK_NOT_NULL(x, key) if (!x) { \
if (error != NULL) \
*error = [NSError parsingErrorFromKey:key]; \
return NO; \
}
#define CHECK_NOT_EMPTY(x, key) if (!x || ![x length]) { \
if (error != NULL) \
*error = [NSError parsingErrorFromKey:key]; \
return NO; \
}
CHECK_NOT_NULL(_ID, kKEY_ID);
CHECK_NOT_EMPTY(_name, kKEY_NAME);
// etc.
return YES;
#undef CHECK_NOT_NULL
#undef CHECK_NOT_EMPTY
}
And then use this in your init method:
- (id)initWithDictionary:(NSDictionary*)dictionary andError:(NSError**)error
{
if (self = [super init]) {
_ID = [dictionary valueForKey: kKEY_ID];
_name = [dictionary valueForKey: kKEY_NAME];
// etc.
if (![self isValid:error]) {
self = nil; // Assuming ARC
}
}
return self;
}
If you create an array of your keys then you can run your check in a loop so you only have one copy of the loop.
Again, using the array you could get all of the keys from the dictionary and remove them from each other. One way will give you new keys and the other way will give you the missing keys.

ASIHTTPRequest completionBlock + ARC

I have the following code to download an image:
imageRequest = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:magazineItem.contentURL]];
__weak ASIHTTPRequest *weakRequest = imageRequest;
__block typeof (self) bself = self;
[imageRequest setCompletionBlock:^{
if (weakRequest.responseStatusCode == 200) {
bself.imageData = weakRequest.responseData;
[[DataAccessLayer sharedInstance] storeTemporaryContentData:bself.imageData url:magazineItem.contentURL];
bself.contentImage = [UIImage imageWithData:bself.imageData];
if (bself.contentImage != nil) {
if (bself.magazineItem.presentationStyle.intValue != -1) {
[bself setPresentationStyle:bself.magazineItem.presentationStyle.intValue];
}
else {
[bself setPresentationStyleForImage:bself.contentImage];
}
}
else
[bself.delegate contentItemViewUnavailable:bself];
}
else {
[bself.delegate contentItemViewUnavailable:bself];
}
}];
[imageRequest setFailedBlock:^{
if (weakRequest.error.code == 4)
return;
[bself.delegate contentItemViewUnavailable:bself];
}];
[imageRequest startAsynchronous];
And though I'm using a __block typeof (self) identifier to pass the self into the block, it still gets retained. I also have tried __weak MyClassName *bself = self; and it still gets into retain cycle. It seem I'm missing something here, can anyone fill me up with what exactly am I doing wrong?
For reference imageRequest is a __strong iVar in my .m file category.
Thanks in advance.
try
__block __unsafe_unretained typeof (self) bself = self;
-- EDIT --
The comment that actually solved the issue
when accesing ivars, do it using bself.property. If you access your ivars directly it will get a retain cycle.
As suggested here Generic typeof for weak self references
__weak __typeof__((__typeof__(self))self) bself = self

Singleton Class 's copyWithZone function causing leaking problem

I detect a memory leakage of [NSCFString copyWithZone:] I did a project search there's only one place using the copyWithZone function that's in the singletonclass.
This macro is widely used. How should I correct that?
#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
\
static classname *shared##classname = nil; \
\
+ (classname *)shared##classname \
{ \
#synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [[self alloc] init]; \
} \
} \
\
return shared##classname; \
} \
\
+ (id)allocWithZone:(NSZone *)zone \
{ \
#synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [super allocWithZone:zone]; \
return shared##classname; \
} \
} \
\
return nil; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
\
Like the comment says, the copyWithZone part is a bit of a red herring.
Look for where you use NSStrings, specifically where you copy them, for example this is a memory leak
#property (nonatomic, copy) NSString* title;
...
self.title = [textView.title retain] // Over retained (and wont show up on the static analyzer)
self.title = #"B";

Imlementation of Singleton Class

i have been using mostly the appDelegate class for global variables but recently i came to know that its not a gud way for keeping global variables so i am trying to make a singleton class as following
#implementation globalVar
static globalVar *_sharedInstance =nil;
#synthesize totalTime;
- (id) init
{
if (self = [super init])
{
}
return self;
}
+ (globalVar *) sharedInstance
{
#synchronized (self) {
if (_sharedInstance == nil) {
[[self alloc] init];
}
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (_sharedInstance == nil) {
_sharedInstance = [super allocWithZone:zone];
return _sharedInstance;
}
}
return nil;
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
-(NSUInteger)retainCount
{
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release
{
// do nothing
}
- (id)autorelease
{
return self;
}
- (void) setTotalTime:(NSString *)time
{
#synchronized(self) {
if (totalTime != time) {
[totalTime release];
totalTime = [NSString stringWithFormat:#"%#",time];
}
}
//NSLog(#"time %#",totalTime);
}
-(NSString *)getTotalTime
{
#synchronized(self) {
//NSLog(#"total %#",totalTime);
return totalTime;
}
}
when i set the value for totaltime in my appDelegate class and retrieve it in that class only i get the correct value. but when i only retrieve the value in some other class i get BAD EXCESS. i first create the sharedinstance and then only call this method then why am i getting this error??
globalVar *myEngine = [globalVar sharedInstance];
NSLog(#"about %#",[myEngine totalTime]);
in my app delegate
globalVar *myEngine = [globalVar sharedInstance];
[myEngine setTotalTime:totalTime];
NSLog(#"in app delegate%#",[myEngine getTotalTime]);
You're releasing totalTime but not retaining the new value, which means that when you access it it's already been released, causing a bad access exception.
You can correct this by changing the line where you set the value to include a call to retain:
totalTime = [[NSString stringWithFormat:#"%#",time] retain];
Have a look at the discussion here:
Is it good practice to use AppDelegate for data manipulation and Handling?

Sinlgeton object in objective C

I need some clarification regarding the singleton object implementation in Objective C. I have implemented the following code for the singleton object ..
static MyClass *instance = nil;
+(MyClass *)getInstance
{
#synchronised(self)
{
if(instance == nil)
{
instance = [[self alloc] init];
}
}
return instance;
}
-(void)dealloc
{
[instance release];
[super dealloc];
}
Does the singleton object requires #synchronised block ???
I have custom defined constructor in my class as follows:
-(id)initWithDefault ..
Does the following line of code creates an issue while allocating for instance
instance = [[self alloc] initWithDefault];
awaiting for your response.
Yes you should. There is a really handy macro by Matt Gallagher that you can use to add singleton support for your class (you just add a SYNTHESIZE_SINGLETON_FOR_CLASS(<class name> inside the implementation block):
#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
\
static classname *shared##classname = nil; \
\
+ (classname *)shared##classname \
{ \
#synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [[self alloc] init]; \
} \
} \
\
return shared##classname; \
} \
\
+ (id)allocWithZone:(NSZone *)zone \
{ \
#synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [super allocWithZone:zone]; \
return shared##classname; \
} \
} \
\
return nil; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
\
- (id)retain \
{ \
return self; \
} \
\
- (NSUInteger)retainCount \
{ \
return NSUIntegerMax; \
} \
\
- (id)autorelease \
{ \
return self; \
}