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.
Related
When I have a method with just a return statement and a value:
-(id)doSomethingCool
{
return [someArray objectAtIndex:2];
}
... is the compiler (or runtime) actually adding an intermediate variable behind the scenes:
-(id)doSomethingCool
{
id someObject = [someArray objectAtIndex:2];
return someObject;
}
I'm guessing at the assembly level it might be doing something like this?
I realize this is an obscure and probably performance-insignificant issue for 99% of applications, but I'm still curious what actually happens behind the curtains in Objective-C if anyone knows.
As an aside, is the only reason people do the first technique just for shorthand convenience, even if over tens of millions of iterations it would be no different had they done it the second way?
Conceptually, that's basically what happens. The value returned from the function is a temporary value. It's actually a copy of whatever value you're returning, which exists until the expression that the method call is used in finishes.
In practice, when you compile with optimizations turned on (in Release mode), the two examples you give will generate identical object code. The difference between the two is largely just down to style, though explicitly storing values in local variables can be useful in debugging.
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.
I read some Objective-C code example, and found some code which uses "block" in the the code. I simplify the example a bit so that it is easy to describe.
Given a block in Objective-C
(void)(^myblock)(int num) = ^{
//do something
}
// somewhere in the code
if(myblock) myblock(3);
// do something
My question:
What is the if(myblock) here?
From the protocol of the block which is return void
I would like someone can explain what is the if(myblock) here for?
First of all: Your example is syntactically incorrect. It should be:
void(^myblock)(int num) = // No parenthesis around void
^{
//do something
}
To your Q:
While it is legal to send a message to a nil object reference, it is illegal to call a NULL block pointer. Please, keep in mind that blocks are an extension to (plain) C and such a call would be a dereference of a NULL pointer, which is illegal in C. Therefore such a code would cause a NULL pointer exception. (On OS X EXC_BAD_ACCESS):
void(^myblock)(int num) = NULL;
myblock(3);
Obviously the developer of the snippet could not guarantee that myblock is different from NULL, so he has to check for it. (Or he is simply afraid of this possibility. In such a case I would prefer to have an exception or at least a log message. However, you find that kind of code fuses, that makes things worse instead of better, many, many times.)
It simply tests if myblock is not nil
myblock is a pointer to the lambda function in modern terminology, it's just kind of hidden by the opaque syntax ObjC uses.
So the if tests if the pointer isn't nil. Whether or not that makes sense or if it's superfluous depends on the missing code. Maybe it overwrote the pointer to nil depending on some condition.
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.
I'm trying to pass an NSString by reference but it doesn't work.
This is the function:
+(void)fileName:(NSString *) file
{
file = #"folder_b";
}
and this is the call:
NSString *file;
[function fileName:file];
nslog(#"%#",file); // and there is nothing in the string....
What I must do to pass my string by reference?
If you want to return a value, then return a value. Pass by reference in Cocoa/iOS is largely limited to NSError**.
Given:
+(void)fileName:(NSString *) file
Then do:
+(NSString *) fileName;
And be done with it.
If you need to return more than one value at a time, that begs for a structure or, more often, a class.
In Objective-C, pass by reference smells like you are doing it wrong.
Pass by reference in Objective-C is reserved largely for returning NSError* information about a recoverable failure, where the return value of the method itself indicates whether or not the requested task succeeded or failed (you can pass NULL as the NSError** argument to allow the method to optimize away creating said error metadata).
Pass by references is also used to retrieve interior state of objects where the return value is effectively a multi-value. I.e. methods from AppKit like the following. In these cases, the pass-by-reference arguments are typically either optional or are acting as secondary return values.
They are used quite sparingly across the API. There is certainly use for pass by reference, but -- as said above -- doing so should be quite rare and rarer still in application code. In many cases -- and in some of the cases below, potentially -- a better pattern would be to create a class that can encapsulate the state and then return an instance of said class instead of pass by reference.
NSWorkspace.h:- (BOOL)getInfoForFile:(NSString *)fullPath application:(NSString **)appName type:(NSString **)type;
NSTextView.h:- (void)smartInsertForString:(NSString *)pasteString replacingRange:(NSRange)charRangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString;
NSAttributedString.h:- (BOOL)readFromURL:(NSURL *)url options:(NSDictionary *)options documentAttributes:(NSDictionary **)dict;
NSNib.h:- (BOOL)instantiateWithOwner:(id)owner topLevelObjects:(NSArray **)topLevelObjects NS_AVAILABLE_MAC(10_8);
NSSpellChecker.h:- (NSRange)checkGrammarOfString:(NSString *)stringToCheck startingAt:(NSInteger)startingOffset language:(NSString *)language wrap:(BOOL)wrapFlag inSpellDocumentWithTag:(NSInteger)tag details:(NSArray **)details NS_AVAILABLE_MAC(10_5);
I believe you're looking for:
+ (void)fileName:(NSString **)file
{
*file = #"folder_b";
}
What's really done here is we're working with a pointer to a pointer to an object. Check C (yup, just plain C) guides for "pointer dereference" for further info.
(...But as has been pointed out repeatedly, in this particular example, there's no reason to pass by reference at all: just return a value.)
Passing a pointer to your object is the Objective C (and C) way of passing by reference.
I agree with 'bbum' that a perceived need to pass by reference is a signal to think about what you are doing; however, it is by no means the case that there are not legitimate reasons to pass by reference.
You should not create classes willy-nilly every time you have a function or method that needs to return more than one value. Consider why you are returning more than one value and if it makes sense to create a class for that then do so. Otherwise, just pass in pointers.
-Just my 2 cents
Try this
+(void)filename:(NSString **)file {
*file=#"folder_b";
}
and send the file as &file like:
NSString *file;
[function fileName:&file];
nslog(#"%#",file);
hope this will work.
I suspect this is because NSString is immutable. Have you tried NSMutableString?