I'm learning to use blocks in my writing but When I try to create one of them the compiler reports a really strange error! For example for the following code:
NSNumber *(^eseguiIlCalcolo)(void)=
^{
};
the compiler reports the following error:
Incompatible block pointer types initializing 'NSNumber
*(^_strong)(void)' with an expression of type 'void(^)(void)'
Where's the error? Can I fix it? Is this related to ARC?
You have declared a block variable which points to a block that returns an NSNumber. However, you tried to initialize it with a block that doesn't return anything. You have to insert a return statement in the body of the block in order the compiler to infer its return type:
NSNumber *(^blk)(void) = ^{
return #(1); // or [NSNumber numberWithInt:1], etc.
};
returns an NSNumber object:
NSNumber * (^ReturnNumber)(void) = ^NSNumber *(void) { // the keyword void is not necessary to write here
return [NSNumber numberWithInt:9];
};
expects an NSNumber object as parameter:
void (^ExpectNumber)(NSNumber *) = ^(NSNumber * number) {
NSLog(#"%#", number);
};
Related
Have a function:
-(void) BlockCall:(void (^)(float a, float b, NSObject *object, NSObject *secObject, NSObject *thirdObject)) argBlock
withObject: (NSObject *)object
andSObj:(NSObject *)sobject
andTObj:(NSObject *)tobject
{
object = [[NSObject alloc] init];
sobject = [[NSObject alloc] init];
tobject = [[NSObject alloc] init];
NSLog(#"First object:%#", object);
NSLog(#"Second object:%#", sobject);
NSLog(#"Third object:%#", tobject);
argBlock(15 ,27, object, sobject, tobject);
}
And varardic block:
jvalue (^voidBlock)(va_list args, ...);
voidBlock= ^(va_list args, ...){
va_arg(parsArgs, double);
va_arg(parsArgs, double);
id NSObjectArg = va_arg(parsArgs, id);
id NSObjectArg2 = va_arg(parsArgs, id);
id NSObjectArg3 = va_arg(parsArgs, id);
va_end(parsArgs);
}
If i call this function with correct parameters and pass this block as parameter. I will get strange result. It will read first and second float, then it will read second passed object as first, and third passed object as second. No matter how many primitives before or if there is no primitives reading va_list will always loose first pointer type.
If i will change this block definition to accept fixed args everything will be ok, but with veridic I always loose first pointer arg
This code doesn't really make any sense. Why would you have a function (block) which both takes a va_list (which is an encoding of another function's varargs) and also varargs? That doesn't make sense. Also, where is parsArgs defined? Why is there no va_start? And who is calling this block? Who is passing this va_list and subsequent arguments?
I've seen many blocks with void return type. But it's possible to declare non-void blocks. Whats the usage of this?
Block declaration,
-(void)methodWithBock:(NSString *(^)(NSString *str))block{
// do some work
block(#"string for str"); // call back
}
Using the method,
[self methodWithBock:^NSString *(NSString *str) {
NSLog(str); // prints call back
return #"ret val"; // <- return value for block
}];
In above block declaration , what exactly is the purpose of NSString return type of the block? How the return value ( "ret val") can be used ?
You can use non-void blocks for the same reason you'd use a non-void function pointer - to provide an extra level of indirection when it comes to code execution.
NSArray's sortUsingComparator provides one example of such use:
NSArray *sorted = [originalArray sortedArrayUsingComparator:(NSComparator)^(id obj1, id obj2){
NSString *lhs = [obj1 stringAttribute];
NSString *rhs = [obj2 stringAttribute];
return [lhs caseInsensitiveCompare:rhs];
}];
The comparator block lets you encapsulate the comparison logic outside the sortedArrayUsingComparator method that performs the sorting.
It's just a return, so you could do something like this to take advantage of the return value and do work on it as well.
-(void)methodWithBlock:(NSString *(^)(NSString *str))block{
// do some work
NSString *string = block(#"string for str"); // call back
// do something with the return string
NSLog(#"%#",string);
}
I'm currently working on a project where the user defines some parameters in a NSDictionnary, that I'm using to setup some objects.
For example, you can ask to create a Sound object with parameters param1=xxx, param2=yyy, gain=3.5 ... Then an Enemi object with parameters speed=10, active=YES, name=zzz ...
{
active = NO;
looping = YES;
soundList = "FINAL_PSS_imoverhere_all";
speed = 100.0;
}
I then instantiate my classes, and would like to set the ivars automatically from this dictionnary.
I've actually wrote some code to check that this parameter exists, but I'm having trouble in actually setting the parameter value, especially when the parameter is non object (float or bool).
Here's what I'm doing so far :
//aKey is the name of the ivar
for (NSString *aKey in [properties allKeys]){
//create the name of the setter function from the key (parameter -> setParameter)
NSString *setterName = [aKey stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[aKey substringToIndex:1] uppercaseString]];
setterName = [NSString stringWithFormat:#"set%#:",setterName];
SEL setterSelector = NSSelectorFromString(setterName);
//Check if the parameter exists
if ([pge_object respondsToSelector:setterSelector]){
//TODO : automatically set the parameter
}
else{
[[PSMessagesChecker sharedInstance]logMessage:[NSString stringWithFormat:#"Cannot find %# on %#", aKey, [dict objectForKey:#"type"]] inColor:#"red"];
NSLog(#"Cannot find %# on %#", aKey, [dict objectForKey:#"type"]);
}
}
}
As you can see, I don't know what to do once I've found that the parameter exists on the object. I tried to use "performSelector... withObject..., but my problem is that some of the parameters are non-objects (float or bool).
I also tried to get the class of the parameter, by using the setter, but it didn't help.
Did anyone manage to do something like that?
Jack Lawrence's comment is spot on.
What you are looking for is called Key Value Coding, or just KVC.
This fundamental part of Cocoa lets you get and set any instance variable using its name as a String and a new value.
It will automatically handle coercing Objects to primitive values, so you can use it for int and float properties too.
There is also support for validating values and handling unknown properties.
see the docs
your code, without validation, could be written
for( id eachKey in props ) {
[anOb setValue:props[eachKey] forKey:eachKey];
}
or just
[anOb setValuesForKeysWithDictionary:props];
as Jack said.
For the non-object parameters you have to put them into an object, for example NSNumber or NSValue. You can then add these objects into your dictionary.
For Example:
float f = 0.5;
NSNumber f_obj = [NSNumber numberWithFloat:f];
I have a class with an initializer that takes a NSDictionary:
-(id)initWithVector:(NSDictionary *) vectorDictionary;
when i try to pass it a NSDictionary, its giving me an error:
Incompatible point types sending'VectorClass * _strong' to parameter
type 'NSDictionary *'
code:
// myVectorList is an array of dictionaries
for (NSDictionary *vector in self.myFielder.myVectorList)
{
if ([vector isKindOfClass:[NSDictionary class]])
{
// hardcoded for testing purposes
if ([[vector objectForKey:HANDLE] isEqualToString:#"pt07p48u17aj75qx8n2fri9jlkrc262yt8"])
{
// GET THE WARNING ON PASSING "VECTOR"
VectorClass *vector = [[VectorClass alloc] initWithVector:vector];
[vector retrieveVectorAttributeTable];
[vector retrieveVectorMetadataTable];
}
}
}
if i typecast (NSDictionary *)vector, no warning.
vector should be a dictionary, so why am i getting the warning?
You use the same name for two different variables. The inner most variable is of type VectorClass defined in the same line, so the compiler tries to pass it to the init method, instead, change its name:
VectorClass *vectorC = [[VectorClass alloc] initWithVector:vector];
[vectorC retrieveVectorAttributeTable];
[vectorC retrieveVectorMetadataTable];
Hee
Does anybody know how to implement an method in objective c that will take an array of arguments as parameter such as:
[NSArray arrayWithObjects:#"A",#"B",nil];
The method declaration for this method is:
+ (id)arrayWithObjects:(id)firstObj...
I can't seem to make such method on my own. I did the following:
+ (void) doSometing:(id)string manyTimes:(NSInteger)numberOfTimes;
[SomeClass doSometing:#"A",#"B",nil manyTimes:2];
It will give the warningtoo many arguments to function 'doSometing:manyTimes:'
Thanks already.
The ellipsis (...) is inherited from C; you can use it only as the final argument in a call (and you've missed out the relevant comma in your example). So in your case you'd probably want:
+ (void)doSomethingToObjects:(id)firstObject, ...;
or, if you want the count to be explicit and can think of a way of phrasing it well:
+ (void)doManyTimes:(NSInteger)numberOfTimes somethingToObjects:(id)firstObject, ...;
You can then use the normal C methods for dealing with ellipses, which reside in stdarg.h. There's a quick documentation of those here, example usage would be:
+ (void)doSomethingToObjects:(id)firstObject, ...
{
id object;
va_list argumentList;
va_start(argumentList, firstObject);
object = firstObject;
while(1)
{
if(!object) break; // we're using 'nil' as a list terminator
[self doSomethingToObject:object];
object = va_arg(argumentList, id);
}
va_end(argumentList);
}
EDIT: additions, in response to comments. You can't pass the various things handed to you in an ellipsis to another function that takes an ellipsis due to the way that C handles function calling (which is inherited by Objective-C, albeit not obviously so). Instead you tend to pass the va_list. E.g.
+ (NSString *)doThis:(SEL)selector makeStringOfThat:(NSString *)format, ...
{
// do this
[self performSelector:selector];
// make string of that...
// get the argument list
va_list argumentList;
va_start(argumentList, format);
// pass it verbatim to a suitable method provided by NSString
NSString *string = [[NSString alloc] initWithFormat:format arguments:argumentList];
// clean up
va_end(argumentList);
// and return, as per the synthetic example
return [string autorelease];
}
Multiple arguments (also known as an arglist) can only come at the end of a method declaration. Your doSomething method would look something like this:
+ (void)doNumberOfTimes:(NSInteger)numberOfTimes withStrings:(id)firstArg, ...
{
va_list args;
va_start(args, firstArg);
NSString * argString = firstArg;
while (argString != nil)
{
// do something with argString here
argString = va_arg(args, NSString *);
}
va_end(args);
}
To be called as follows:
[SomeClass doNumberOfTimes:2 withStrings:#"A", #"B", nil];
See also: How to create variable argument methods in Objective-C
I think you're after a variadic function. Here's Apple's documentation: http://developer.apple.com/library/mac/qa/qa2005/qa1405.html