Override setter in Objective-c. Why check is equal parameter - objective-c

Often find custom setter sintaxis like this:
- (void)setParentCatalog:(Catalog *)parentCatalog {
if (_parentCatalog != parentCatalog) { //???
_parentCatalog = parentCatalog;
[self refresh];
}
}
Why i should check?
if (_parentCatalog != parentCatalog)

This checks if both _parentCatalog and parentCatalog are pointing to the same memory location.
If both are same object then no need to set the objectValue.

The reason for checking if the two are equal is to avoid executing code when it's not necessary. If the method is called very often, this could have a performance benefit. Under non-ARC, your code might look more like this:
- (void)setParentCatalog:(Catalog *)parentCatalog {
if (_parentCatalog != parentCatalog) {
[_parentCatalog release];
[parentCatalog retain];
_parentCatalog = parentCatalog;
[self refresh];
}
}
So, by checking that what you received is actually a new value, you avoid those retain and release calls happening (which are still there with ARC). You've also got [self refresh] in there, which probably doesn't need to happen unless the value has actually changed.

The idea here is that if the parameter passed in to the setter is the same object already stored in the property, then there is no need to call [self refresh] again.
A refresh method often reads in data, works on it and then re-displays it in the app's views. No need to do all this work again if the data in the property haven't really changed.

It's a decision that is use case dependant. The idea behind this guard is to prevent doing unnecessary work.
If you imagine that your [self refresh] kicked off a very expensive operation then you would be reluctant to do it every time. So if you only do it when the object actually changes you save yourself some work.
Of course this may well be the behaviour you are looking for in which case you would need to stick the [self refresh] call outside of the guard.
Like all code examples you find it's worth weighing up the trade offs of the implementation and then you can better decide what you need in your case.

Related

How can I solve "Collection was mutated while being enumerated", #synrchonized, mutableCopy, or something else?

In Crashlytics, I'm seeing a crash that my users are experiencing quite infrequently. The offending code looks like this...
- (void)updateIsAnsweredField:(NSArray *)moduleItemsList
{
if (moduleItemsList && self.answeredItems && self.answeredItems.count > 0) {
for (ModuleItem * item in moduleItemsList) { // "Collection was mutated while being enumerated"
if ([item isKindOfClass:[ModuleItem class]] && [item shouldCheckIfAnswered]) {
item.answered = [self isAnsweredItem:item.moduleID];
}
}
}
}
The error given by Crashlytics can be seen in a comment in the code snippet above.
I assume there are a few ways to go about solving this.
1) wrap everything inside the function in #synchronized(moduleItemsList) {}. Is this the ideal way to solve? I've heard #synchronized is very slow and to avoid it when possible.
2) Create a copy a la NSMutableArray *copyModuleItemsList = [moduleItemsList mutableCopy];. Then enumerate that. Would this solve the issue? I would assume it would solve this particular issue, but there would be another problem no? That being... at the end when we go to assign our copy back to our original a la moduleItemsList = copyModuleItemsList;, moduleItemsList may have changed in the meantime on a different thread.
3) Trace the passed in :(NSArray *)moduleItemsList to whomever holds it as a property. Then overwrite the getter to use dispatch_sync, and the setter to use dispatch_barrier_async. However, there is no guarantee that the original array is a property of any class whose getter and setter can be overridden. And actually, none of this makes sense since we wouldn't be specifically changing that array would we?
I'm a bit confused. Can anyone assist in this matter? Is #1 the option I want?
EDIT: Adding more code
[item shouldCheckIFAnswered]:
This just checks a #property value that exists on the ModuleItem class. if self.moduleType == ModuleTypeSuchAndSuch
isAnsweredItem::
- (BOOL)isAnsweredItem:(NSString *)moduleID
{
if (!self.answeredItems) {
return NO;
}
return [self.answeredItems containsObject:moduleID];
}
From your post, it sounds like the moduleItemsList is getting modified in another thread. The "correct" way to fix this is going to depend on what the desired relationship between the state in the other thread and the state in this thread is.
If you use #synchronized(moduleItemsList) in both this code, and in the code that modifies the collection in the other thread, then when this code runs, it'll always have an "up to date" view of moduleItemsList.
If you copy the moduleItemsList into another object, then when this code runs, it might set the answered value on an item that's no longer in the moduleItemsList, or it might fail to set the answered flag on an item that was recently added to moduleItemsList.
In general, the #synchronized version is the easier way to get "correct" behavior. You'd only want to use copy if you're sure that it doesn't matter that the two threads may disagree about the current contents of moduleItemsList.
I've heard #synchronized is very slow and to avoid it when possible.
This is terrible advice, in general. #synchronized is just as slow as it needs to be to ensure consistent state between threads, and to provide a re-entrant lock. You don't want to just throw #synchronized around everything, willy-nilly, but it's a fine solution to synchronizing data access between threads - that's what it's for, after all.

Return value from asynchronous SQL method

I have this code:
- (NSString *)obtenerDatosUsuario
{
__block NSString *result=#"";
[self obtenerDatosUsuarioSQL:^(NSString *resultadoSQL){
result=resultadoSQL;
}];
return result;
}
And I want that the return be the content of resultadoSQL
If my guess is correct about what happens inside your method -obtenerDatosUsuarioSQL: (i.e., it performs a lengthy operation in a background thread, and gives the result to the passed block argument), then your code runs in the following order:
You call -obtenerDatosUsuario
You call -obtenerDatosUsuarioSQL:, passing a completion handler block.
Execution proceeds forward and reaches the return statement at the end of -obtenerDatosUsuario, and exits the method body. The returned variable result hasn't been set yet!
Sometime later, the SQL query completes and the block is executed. But it is too late to return the result because execution already exited the method -obtenerDatosUsuario.
There are ways to make this asynchronous method behave synchronously (e.g. semaphores), but it generally is a very, very bad idea. Most likely, obtenerDatosUsuarioSQL is asynchronous because there is a chance (even if only a small chance) that the result won't be returned immediately. Maybe it's possible that the SQL will be slow. Or maybe you'll eventually be doing queries from multiple threads, so this query might have to wait for queries in other threads to finish. Or there might be other reasons. But whatever the reason, this method was implemented as asynchronous method, and you should embrace that, rather than fight it. If you change obtenerDatosUsuario to return synchronously, you open yourself to a wide variety of possible problems.
Instead, you should just adopt asynchronous pattern in your code. For example, let's imagine that you have some code that was planning on using the result of obtenerDatosUsuario for some other purpose, e.g.:
NSString *resultadoSQL = [self obtenerDatosUsuario];
// use `resultadoSQL` here
Just change that to:
[self obtenerDatosUsuarioSQL:^(NSString *resultadoSQL){
// use `resultadoSQL` here
}];
// but not here
And, if you're using obtenerDatosUsuarioSQL in some method that you're currently trying to return the value immediately, then change that to behave asynchronously, too. For example, let's assume you had something like:
- (NSString *)someOtherMethod {
NSString *resultadoSQL = [self obtenerDatosUsuario];
// let's assume you're doing something else with `resultadoSQL` to build some other string
NSString *string = ... // some expression using `resultadoSQL`
return string;
}
Then, you'd change that to also adopt asynchronous pattern:
- (void)someOtherMethod:(void (^)(NSString *))completionHandler {
[self obtenerDatosUsuarioSQL:^(NSString *resultadoSQL){
NSString *string = ... // some expression using `resultadoSQL`
completionHandler(resultadoSQL);
}];
}
When you first encounter this, this may seem unnecessarily complicated, but asynchronous programming is so critical, such a fundamental part of Cocoa programming, that one really must gain some familiarity with these common asynchronous patterns, such as blocks. Personally, we use block syntax so much that I create code snippets in Xcode's "Code Snippet Library" for typical block patterns, which simplifies life a lot and gets you out of the world of memorizing the unintuitive block syntax.
But don't be tempted to wrap asynchronous method in another method that makes it behave synchronously. You open yourself up to many types of problems if you do that.

Set a BOOL right after checking it

I'm working through someone else's codebase and there are several lines like this:
if (self.aBooleanProperty) {
self.aBooleanProperty = YES;
// Do some stuff
}
Is there any point to setting it to YES right after checking it? Is there something I'm missing here?
if (self.aBooleanProperty) {
self.aBooleanProperty = YES;
// Do some stuff
}
In properly written code, you aren't missing anything and that setter line increases the billable lines of code by one with a no-op.
There are two reasons, though, that this could be done for misguided reasons.
As #HotLicks said, there may be side effects to the setter that might need to be triggered. But they should have been triggered on set unless the developer had the misguided notion of setting the ivar directly everywhere and then using the above to coalesce the cost of setting to one spot. But that'd be a remarkably fragile and silly thing to do.
The other reason is because, traditionally, Objective-C's BOOL is a glorified char. Only it isn't so glorified. Thus, comparing a BOOL to YES is actually dangerous because YES has an explicit value.
BOOL mmmmmK = 2; // this is valid
if (mmmmmK == YES) { /* this won't execute */ }
Sort of like when climbing a cliff and something starts falling, you don't yell "bottle", "shoe", "pebble", or "prosthetic limb", but you always yell ROCK.
So, maybe the developer was thinking of normalizing the affirmative with an explicit YES. Again, quite doubtful and, even if that is the case, then it should raise suspicion about the quality of the rest of the codebase.
Ouch.
This is difficult to tell without having more code. I think everybody will agree the code appears to be wrong, however, what we are seeing is an obj-c property - the previous programmer could do some "clever" thing, e.g. it's possible that the getter of aBooleanProperty sets itself to NO when you call it.
Before modifying the code, check the getters. This reminds me of schrödinbug
I think the person miswrote YES, instead should've written NO as it already is YES when it checked in the condition. Or otherwise there isne any point to that line.
if
self.aBooleanProperty = YES;
is included in the braces,it is not needed and if it is
self.aBooleanProperty = NO;
is included ,then it is logical

Conditional value (like while loop) as method parameter

So, I'm attempting to have a method that effectively does this:
- (void)doWhile: (/*some magical type*/)condition
{
while (condition)
{
// do some magical things
}
}
And while your first suggestion might be a BOOL consider the following exceptions:
[someObject doWhile: someOtherObject];
// yes, I know that I could just do (someOtherObject != nil), but
// I should be able to just use (someOtherObject), right?
// seeing as how ifs/fors/whiles can use just the object.
[someObject doWhile: [someOtherObject isValid]];
// since -isValid returns a BOOL, this will work, but it will only
// pass the value of -isValid at the time of calling to the while loop.
// if the value of -isValid changes, -doWhile: will have no idea of the change,
// whereas while() would.
The use of the primitive _Bool allows me to solve the former problem, however the latter problem still persists. Is there some way to evaluate the truthfulness of a type-agnostic parameter identically to how while() works?
As noted in comments, passing a block is a versatile way of getting the desired result even though simpler methods may be appropriate for the test cases where a completely dynamic evaluation isn't required.

Array, memory management

I have some code where I implemented undo functionality, the undo function is as follows:
- (void) undo
{
drawImage.image = pathArray.lastObject;
[pathArray removeLastObject];
}
Then I have one more function to capture the current image from the screen; in this function I am getting EXC_Bad_ACCESS error on this
[pathArray removeLastObjectatIndex:0];
No other calls of functions are made in this part of program. Maybe there could be a problem of moving whole array, but I don't want to use undo manager.
Is there any better way, to get the last object of an array and then remove the first one and move whole array by one?
Notice : path array is MutableArray *patharray;
Thanks all!=)
I just don't have and idea how to solve this. I didn't find any solution in the official docs.
Ultimately, this program would not likely be reachable -- It implies there is nothing to 'undo' in many contexts, and the option should not be given. Your problem often ultimately lies upstream.
If that is not quite the case here, here is one approach:
- (void)undo
{
if (0 == self.pathArray.count) {
self.drawImage.image = nil;
return;
}
self.drawImage.image = self.pathArray.lastObject;
[self.pathArray removeLastObject];
}
As well, [pathArray removeLastObjectatIndex:]; is not a real selector.
Update
See my answer here to enable and find zombies, and locate the reference count offset quickly. Your program should never message a zombie.