Incompatible block pointer SKSpriteNode - ios

This is my code
- (void) update:(NSTimeInterval)currentTime
{
[self.children enumerateObjectsUsingBlock:^(SKSpriteNode * child, NSUInteger idx, BOOL *stop) {
child.position = CGPointMake(child.position.x-self.scrollingSpeed, child.position.y);
if (child.position.x <= -child.size.width){
float delta = child.position.x+child.size.width;
child.position = CGPointMake(child.size.width*(self.children.count-1)+delta, child.position.y);
}
}];
}
And i am getting an an error
Incompatible block pointer types sending 'void (^)(SKSpriteNode *__strong, NSUInteger, BOOL *)' to parameter of type 'void (^ _Nonnull)(SKNode * _Nonnull __strong, NSUInteger, BOOL * _Nonnull)'
and I don't know why. I tried changing it to SKNode but it says size does not exist.
Any ideas would be greatly appreciated.

The enumeration block syntax is not correct, you need to change:
[self.children enumerateObjectsUsingBlock:^(SKSpriteNode * child, NSUInteger idx, BOOL *stop)
{
child.position = CGPointMake(child.position.x-self.scrollingSpeed, child.position.y);
if (child.position.x <= -child.size.width)
{
float delta = child.position.x+child.size.width;
child.position = CGPointMake(child.size.width*(self.children.count-1)+delta, child.position.y);
}
}];
to
[self.children enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop)
{
SKSpriteNode *child = (SKSpriteNode *)object;
child.position = CGPointMake(child.position.x-self.scrollingSpeed, child.position.y);
if (child.position.x <= -child.size.width)
{
float delta = child.position.x+child.size.width;
child.position = CGPointMake(child.size.width*(self.children.count-1)+delta, child.position.y);
}
}];
The enumeration block's first parameter is of type id not SKSpriteNode. There is no such implementation for NSArray.

Related

I have a class I want some method transfer to an array's object

Like the title said: I have a ObjcClass
I want some thing can be reused ,
because the class may have
-(void)test1:xxx -(void)test2:xxx argu:yyy
I don't want to do that
[dispatchArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[obj test2:xxx argu:yyy];
}];
example:
- (void)test:(NSString *)argument1 {
NSArray *dispatchArray = #[];//If the array is initialized with multiple objects
//I want each object to call the "test:" method unlike the following
// [dispatchArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// [obj performSelector:#selector(test:) withObject:argument1];
// // or [obj test:argument1];
// }];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[_services enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
if ([obj respondsToSelector:_cmd]) {
[obj application:application didFinishLaunchingWithOptions:launchOptions];
}
}];
return YES;
}
like this ,UIApplicationDelegate has a number of method ,I don't want write [obj application:application didFinishLaunchingWithOptions:launchOptions]; or [obj applicationWillResignActive:application]; at every method,On the contrary I hope that method like [obj respondsToSelector:_cmd] ,that I can propose as a general method like [obj invokeWithMethod:_cmd arguments:_VA_LIST];
Whether these methods can be optimized,because they do the same thing to different method
The methods you app delegate has been implemented, you should implement as before. To the method in UIApplicationDelegate protocol which your app delegate did not implement, you can use message forwarding to achieve your target. Override the message forwarding methods of your app delegate as below:
- (BOOL)respondsToSelector:(SEL)aSelector {
struct objc_method_description desc = protocol_getMethodDescription(objc_getProtocol("UIApplicationDelegate"), aSelector, NO, YES);
if (desc.name != nil) {
return YES;
}
return [super respondsToSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
SEL selector = [anInvocation selector];
struct objc_method_description desc = protocol_getMethodDescription(objc_getProtocol("UIApplicationDelegate"), selector, NO, YES);
if (desc.name != nil) {
[_services enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj respondsToSelector:selector]) {
[anInvocation invokeWithTarget:obj];
}
}];
}
}
Get the return values:
NSMutableArray *returnValues = [NSMutableArray array];
[_services enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
id returnValue = [NSNull null];
if ([obj respondsToSelector:selector]) {
[anInvocation invokeWithTarget:obj];
const char *returnType = anInvocation.methodSignature.methodReturnType;
if( !strcmp(returnType, #encode(void)) ){
//If the return value is `void`, just set returnValue = [NSNull null]
} else if( !strcmp(returnType, #encode(id)) ){
// if the return type is derived data types(`id`)
[anInvocation getReturnValue:&returnValue];
}else{
//if the return value is basicdata type
NSUInteger length = [anInvocation.methodSignature methodReturnLength];
void *buffer = (void *)malloc(length);
[anInvocation getReturnValue:buffer];
if( !strcmp(returnType, #encode(BOOL)) ) {
returnValue = [NSNumber numberWithBool:*((BOOL*)buffer)];
} else if( !strcmp(returnType, #encode(NSInteger)) ){
returnValue = [NSNumber numberWithInteger:*((NSInteger*)buffer)];
}
returnValue = [NSValue valueWithBytes:buffer objCType:returnType];
}
}
// If the `obj` can not responds to selector, or the return value is void(nil), we set the `returnValue = [NSNull null]`
[returnValues addObject:returnValue];
}]
Looks like you just want to loop through the objects in the array. This is not very Type safe. All objects must provide a "test" method. If they're all the same Class that would be better than using NSObject.
for (NSObject *obj in dispatchArray) {
[obj performSelector:#selector(test:) withObject:argument1];
}

How do you return the item found by enumerateObjectsUsingBlock?

I have an NSMutableOrderedSet.
I need to enumerate it, and it looks like the only options built onto the set are block based. So picking the simplest of the block based options, I have something like this...
[anNSMutableOrderedSet enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([(SomeClass*)obj isWhatIWant]) {
*stop = YES;
// Ok, found what I'm looking for, but how do I get it out to the rest of the code?
}
}]
You can use __block to assign some value inside completion block.
__block yourClass *yourVariable;
[anNSMutableOrderedSet enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([(SomeClass*)obj isWhatYouWant]) {
yourVariable = obj;
*stop = YES;
}
}]
NSLog(#"Your variable value : %#",yourVariable);
You will need to pass in a call back/block of code to call out to.
- (void)someMethod
{
[self enumerateWithCompletion:^(NSObject *aObject) {
// Do something with result
}];
}
- (void)enumerateWithCompletion:(void (^)(NSObject *aObject))completion
{
[anNSMutableOrderedSet enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([(SomeClass*)obj isWhatIWant]) {
*stop = YES;
if (completion) {
completion(obj);
}
}
}];
}
You could also use delegation, and call back to a delegate you have defined to return the object.
[self.delegate enumerationResultObject:obj];
UPDATE:
Realised enumerateObjectsUsingBlock: is actually called synchronously, so the better approach would be to use a __block variable. Callback would still work but could be construed as misleading.
In this case, the easiest thing would be to not use enumerateObjectsUsingBlock:, and just use fast enumeration instead:
for (SomeClass *obj in anNSMutableOrderedSet) {
if ([obj isWhatIWant]) {
yourVariable = obj;
break;
}
}
Try With Weak Self
__weak SomeClass *weakSelf = self;
[anNSMutableOrderedSet enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([(SomeClass*)obj isWhatIWant]) {
weakSelf = (SomeClass*)obj;
*stop = YES;
// Ok, found what I'm looking for, but how do I get it out to the rest of the code?
}
}];
//you Have to use weakSelf outside the block

NSPredicate to fetch dictionary from array of arrays

From the following array I want to fetch dictionary with message_id = 1. Basically I want to get the indexpath of the cell whose message_id == 1.
<__NSArrayM 0x17d918d0>(
<__NSArrayM 0x17faa070>(
{
chatStatus = sent;
date = "Feb 05, 2016";
from = "";
height = "17.000000";
isOutgoing = yes;
"message_id" = "1";
time = "02:39 PM";
to = "";
width = "95.000000";
},
{
chatStatus = sent;
date = "Feb 05, 2016";
from = "";
height = "17.000000";
isOutgoing = yes;
"message_id" = "2";
time = "02:39 PM";
to = "";
width = "95.000000";
},
)
)
I think you should look around the NSArray's method
-[NSArray indexesOfObjectsPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)]
by doing something like that :
NSMutableArray *indexPaths = [NSMutableArray array];
[myArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger firstIndex, BOOL * _Nonnull stop) {
NSArray *messages = (NSArray*)obj;
NSIndexSet *indexes = [messages indexesOfObjectsPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSDictionary *message = (NSDictionary*)obj;
if (message.message_id == 1) {
return YES;
}
return NO;
}];
[indexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
[indexPaths addObject:[NSIndexPath indexPathForRow:idx inSection:firstIndex]];
}];
})];
It's seems a bit tricky, and I did it quickly so that I think you could improve it. The idea is to enumerate through your first array, and then use "indexesOfObjectsPassingTest" to get all indexes for your matching objects. And then you and your indexPaths by going through the enumeration of the NSIndexSet object :)
I think you could even do it recursively, so that you won't be limited by the depth of your arrays which is, here, only 2 :/
Hope it helped \o
Bilkix.

SKSpriteNode return null name

Why the created name of a sprite isn't saved or even returned ?
I add several objects (SKSpriteNode) in the init of the Scene
-(id)initWithSize:(CGSize)size {
NSArray *oxyObjects = [self.oxygens objectsNamed:#"oxy"];
for (NSDictionary *enemyObj in oxyObjects) {
SKSpriteNode *oxyNode = [SKSpriteNode spriteNodeWithImageNamed:#"oxygen"];
NSString *valeurX=enemyObj[#"x"];
float x = [valeurX floatValue];
NSString *valeurY=enemyObj[#"y"];
float y = [valeurY floatValue];
CGPoint oxyPosition = CGPointMake(x, y);
oxyNode.position = oxyPosition;
oxyNode.name = #"ballOxygen";
NSLog(#"oxy %#",oxyNode);
[self.map addChild:oxyNode];
}
The log give me this with the correct name for the sprite
oxy name:'ballOxygen' texture:[ 'oxygen#2x.png' (24 x 24)] position:{454, 99} size:{12, 12} rotation:0.00
To check collision, I tried to use
[[self children] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
SKNode *node = (SKNode *)obj;
NSLog(#"obj : %#", obj);
Or this
NSArray *nodes = self.children;
for(SKNode * node in nodes){
SKSpriteNode *obj = (SKSpriteNode *) node;
NSLog(#"obj : %#", obj);
But It return always a null name
obj : name:'(null)' texture:[ 'Bird1#2x.png' (8 x 24)] position:{100, 100} size:{17, 12} rotation:0.00
My best guess:
You are adding oxyNode to self.map but you are enumerating self.children where you probably should be enumerating self.map.children.
Try this:
[self.map.children enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
SKNode *node = (SKNode *)obj;
NSLog(#"obj : %# (%p)", obj, obj);
}];

Enumerate NSArray starting at center / middle of array searching both ways

How can I enumerate an array starting at the center of the array?
#implementation NSArray (Extensions)
- (void)enumerateFromCenterGoBothWaysUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
{
NSMutableArray *copy = [self mutableCopy];
BOOL shouldStop = NO;
while([copy count] > 0 && shouldStop == NO)
{
NSUInteger index = [copy count] / 2;
id obj = copy[index];
[copy removeObject:obj];
block(obj, index, &shouldStop);
}
}
#end

Resources