When I've set a breakpoint to the first for loop, I've noticed that it's being executed but the value is not being updated to the string "Viki". Instead it's just being NULL.
Also, the last line of code NSLog(#"Mahal"); is not executed. Why?
NSMutableArray *arr1;
for(int i=0; i<3; i++)
{
[arr1 addObject:#"Viki"];
}
NSLog(#"Hello");
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"Taj");
for(int i=0; i<3; i++)
{
NSLog(#"%#", [arr1 objectAtIndex:i]);
}
dispatch_sync(dispatch_get_main_queue(), ^{ // 2
NSLog(#"Mahal"); // 3
});
});
You didn't initialize arr1 to point to an actual array object. You've only declared the pointer variable, you've never made it point to anything. It defaults to nil and all messages to nil return nil (or other zero-valued result appropriate for the type).
You could have discovered this had you ever logged the value of arr1.
Related
I have two arrays: array1 and array2. Each object of arrays is an array too (2D arrays). In this way I multiple them. So how I have big arrays I use dispatch_apply. Every time i receive different results include a right result. Maybe somebody knows how to fix it?
dispatch_apply([array2 count], queue, ^(size_t j)
{
k = 0;
for (int l = 0; l < [[array1 objectAtIndex:0] count]; l++) {
k += [[[array1 objectAtIndex:i] objectAtIndex:l] intValue] *
[[[array2 objectAtIndex:j] objectAtIndex:l] intValue];
}
kNSNumber = [NSNumber numberWithInt:k];
[multipliedArrayInto replaceObjectAtIndex:j withObject:kNSNumber];
});
[resulArray insertObject:multipliedArrayInto atIndex:i];
}
There's two things, I can suggest, and I bet one of them (or both) is the overarching solution to your problem.
First, I would declare k local to the block, so there would be no question that you are overwriting it or not. You likely have the same problem with kNSNumber inside the block. If you are just using that NSNumber instance to slam into the multipliedArrayInto accumulator, you may as well remove kNSNumber, and use #(k) in it's place (if only to be more readable). Similarly, make sure multipliedArrayInto is declared just before the dispatch_apply, in what looks like an outer for loop (where ever i is coming from). And finally, make sure resulArray is instantiated, or otherwise readied just before that outer for loop.
Second, is queue a concurrent or serial queue? If you are using dispatch_apply like a parallel-executing for/enumeration -- which is likely, I think, so you are taking about handling "big arrays" efficiently -- then you are practically guaranteeing that k is being overwritten. If you change it to serial, it may work as designed. If you want it to be parallel, you will need to move the declaration of your k accumulator inside the block, and make sure the declaration of other variables makes sense, too.
Update to reflect question updates:
#antonytonies ideally, your followup answer on this thread should be moved into the question itself, so that people can follow this thread easier.
So, it looks like what I described is exactly your problem.
The global queues are all concurrent queues, which means that (hypothetically) all the dispatch blocks are executing at once, and the contents of k and other variables are getting blown away depending on how the order of the blocks executes.
I've taken your update (in the "answer" you added), and modified it to probably work:
// I renamed your method, because nameless parameters pain me. This is cosmetic, and doesn't
// matter for the problem at hand.
- (NSMutableArray *)multiplicationArrays:(NSMutableArray *)array vector:(NSMutableArray *)vector
{
// IMHO, you want to set resultArray to nil here. Another option is to set it to nil in the
// else case, below. Properties in Objective-C are initalized to nil,0,false,etc; you can
// rely on ARC to initialize pointer to objc objects on the stack, too. However, someone
// reading this code may or may not know that. IMHO, using the explicitly assignement makes it
// clear that you're going to be returning `nil` or an instance of `NSMutableArray`.
NSMutableArray *resultArray = nil;
if ([[array objectAtIndex:0] count] == [vector count]) {
// Nicely done w/ pre-allocating the result array here, so that there's no question
// of the indexes matches the results later on.
resultArray = [[NSMutableArray alloc] initWithCapacity:[array count]];
for (int i=0; i < [array count]; i++) {
[resultArray insertObject:[NSNull null] atIndex:i];
}
// 'queue' here is a concurrent queue. This means that you are proclaiming to the runtime
// that the blocks being executed are able to operate correctly w/o interference from each
// other. This is also thought of in terms of parallel execution: all these blocks may run
// **at once**. This *also* means, that you must not share storage between them.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply([array count], queue, ^(size_t j) {
// Moved 'result' inside the block.
NSInteger result = 0;
for (int l = 0; l < [[array objectAtIndex:0] count]; l++) {
// These array reads are **NOT** thread safe. They probably don't cause must trouble in
// practice, but you may want to reconfigure this.
result += [[[array objectAtIndex:j] objectAtIndex:l] intValue] * [[vector objectAtIndex:l] intValue];
}
// The replace of the object into resultArray is **NOT** thread-safe.
// This probably hasn't caused you much trouble, since you can guarantee that
// you aren't writing at the same index. However, I would strongly suggest to
// change this to be thread-safe.
[resultArray replaceObjectAtIndex:j withObject:#(result)];
});
}
else {
NSLog(#"matrix count isn't correspond");
}
return resultArray;
}
Finally: consider just using Apple's Accelerate framework for this sort of problem solving. It's available on OSX and iOS, so you should have all of your bases covered.
it's the same thing if I multiple 2D-array and vector
-(NSMutableArray*)multiplicationArraysWithVector:(NSMutableArray *)array :(NSMutableArray *)vector
{
NSMutableArray* resultArray;
if ([[array objectAtIndex:0] count] == [vector count])
{
resultArray = [[NSMutableArray alloc] initWithCapacity:[array count]];
for (int i=0; i < [array count]; i++) {
[resultArray insertObject:[NSNull null] atIndex:i];
}
__block NSInteger result;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply([array count], queue, ^(size_t j)
{
result = 0;
for (int l = 0; l < [[array objectAtIndex:0] count]; l++) {
result += [[[array objectAtIndex:j] objectAtIndex:l] intValue] * [[vector objectAtIndex:l]intValue];
}
[resultArray replaceObjectAtIndex:j withObject:#(result)];
});
}
else
{
NSLog(#"matrix count isn't correspond");
}
return resultArray;
}
In this case I can get a right or wrong data result.
Trying to understand how blocks working in objective-c. Got next question while reading apple's docs (link)
Here is an example how we should no use blocks:
void dontDoThis() {
void (^blockArray[3])(void); // an array of 3 block references
for (int i = 0; i < 3; ++i) {
blockArray[i] = ^{ printf("hello, %d\n", i); };
// WRONG: The block literal scope is the "for" loop.
}
}
But how we could get 3 different blocks that will print "hello, 0", "hello, 1" and "hello, 2"? I tried many different ways but every time I got "hello, 2" three times.
A block starts out life on the stack and, thus, a block's lifespan is only as long as the scope it is declared in.
The body of a for() loop -- the body of the loop in the {}s -- is a scope in and of itself. Thus, your code is putting a reference to something on the stack [the block] into a variable in the surrounding scope [the language array].
You need to copy the block to the heap to have it survive:
void dontDoThis() {
void (^blockArray[3])(void); // an array of 3 block references
for (int i = 0; i < 3; ++i) {
blockArray[i] = [^{ printf("hello, %d\n", i); } copy];
}
}
If not using ARC, you would also need to -release the copied blocks at some point.
You might find this weblog post handy (I wrote it shortly after Blocks were made public). This one goes into a few tips, tricks, and gotchas.
Wait -- yeah -- you're correct. There is magic going on in the ARC compiler that is causing the blocks to seemingly be on the heap magically. However, I can't find anything in the LLVM documentation that explicitly documents this behavior. If you turn off ARC, you'll see the output be something like 2,2,2 instead of 0,1,2.
This is somewhat new behavior. I wouldn't rely on this behavior until someone can find the explicit note in the compiler that defines exactly how this is supported.
#autoreleasepool {
void (^blockArray[3])(void); // an array of 3 block references
for (int i = 0; i < 3; ++i) {
void (^block)(void) = ^{ printf("hello, %d\n", i); };
NSLog(#"%p", block);
blockArray[i] = block;
NSLog(#"%p", blockArray[i]);
}
for (int i = 0; i < 3; ++i) blockArray[i]();
}
Outputs:
2012-12-24 16:15:36.752 jkdfjkfdjkdfjk[70708:303] 0x7fff5fbff838
2012-12-24 16:15:36.755 jkdfjkfdjkdfjk[70708:303] 0x100108160
2012-12-24 16:15:36.758 jkdfjkfdjkdfjk[70708:303] 0x7fff5fbff838
2012-12-24 16:15:36.759 jkdfjkfdjkdfjk[70708:303] 0x100108000
2012-12-24 16:15:36.760 jkdfjkfdjkdfjk[70708:303] 0x7fff5fbff838
2012-12-24 16:15:36.760 jkdfjkfdjkdfjk[70708:303] 0x100102e70
hello, 0
hello, 1
hello, 2
Thus, the block is created on the stack and copied to the heap automatically on the assignment outside of the scope of the for() loop.
A similar test also reveals that the block will be copied when passed as an argument to NSArray's addObject:.
If you really wanted to get this to work you could use an NSMutableArray instead of a C array.
NSMutableArray *blocks = [NSMutableArray array];
for (int i = 0; i <= 3; i++) {
blocks[i] = ^{ printf("hello %d\n", i); };
}
By adding them to an NSMutableArray they will be copied off of the stack and onto the heap allowing them to outlive the scope of the for loop.
As #bbum points out the above does not work, I took the idea that blocks just work with ARC too far.
You would need to actively copy the blocks for them to work... so the following should work
NSMutableArray *blocks = [NSMutableArray array];
for (int i = 0; i <= 3; i++) {
blocks[i] = [^{ printf("hello %d\n", i); } copy];
}
i'm trying to get the values of an array randomly but i'm getting an error
here is my code so far:
NSMutableArray *validMoves = [[NSMutableArray alloc] init];
for (int i = 0; i < 100; i++){
[validMoves removeAllObjects];
for (TileClass *t in tiles ) {
if ([self blankTile:t] != 0) {
[validMoves addObject:t];
}
}
NSInteger pick = arc4random() % validMoves.count;
[self movePiece:(TileClass *)[validMoves objectAtIndex:pick] withAnimation:NO];
}
The error you're getting (an arithmetic exception) is because validMoves is empty and this leads to a division by zero when you perform the modulus operation.
You have to explicitly check for the case of an empty validMoves array.
Also you should use arc4random_uniform for avoiding modulo bias.
if (validMoves.count > 0) {
NSInteger pick = arc4random_uniform(validMoves.count);
[self movePiece:(TileClass *)[validMoves objectAtIndex:pick] withAnimation:NO];
} else {
// no valid moves, do something reasonable here...
}
As a final remark not that arc4random_uniform(0) returns 0, therefore such case should be avoided or you'll be trying to access the first element of an empty array, which of course will crash your application.
I have done a bit of searching and not really found an answer to my question.
The code below is trying to copy the contents of a NSMutable array that contains some objects.
I have tried the code below however when run there is no error, but the new arrays do not get the objects as I would have thought they would.
csvContent is a array that contains objects from parsing a CSV file and the other NSMutable arrays round1, round2 etc have been defined in the header file.
The NSLOG output is correct but the arrays contain no objects.
for(int loopNumber = 0; loopNumber < [csvContent count]; loopNumber++)
{
if ([[[csvContent objectAtIndex:loopNumber] objectAtIndex:1] isEqualToString:#"1"])
{
[round1 addObject:[csvContent objectAtIndex:loopNumber]];
NSLog(#"round 1");
}
if ([[[csvContent objectAtIndex:loopNumber] objectAtIndex:1] isEqualToString:#"2"])
{
[round2 addObject:[csvContent objectAtIndex:loopNumber]];
NSLog(#"round 2");
}
if ([[[csvContent objectAtIndex:loopNumber] objectAtIndex:1] isEqualToString:#"3"])
{
[round3 addObject:[csvContent objectAtIndex:loopNumber]];
NSLog(#"round 3");
}
}
Did you actually create and initialize the arrays for round1, round2, and round3? In other words, make sure they are not nil when this loop is run.
Also, your code is terribly inefficient. You call [csvContent objectAtIndex:loopNumber] six times inside the loop. Try this (I'm using i instead of loopNumber to save typing):
for (int i = 0; i < csvContent.count; i++) {
NSArray *loopContent = csvContent[i];
NSString *val = loopContent[1];
if ([val isEqualToString:#"1"]) {
[round1 addObject:loopObject];
} else if ([val isEqualToString:#"2"]) {
[round2 addObject:loopObject];
} else if ([val isEqualToString:#"3"]) {
[round3 addObject:loopObject];
}
}
Blocks are fine but what about writing C arrays?
Given this simplified situation:
CGPoint points[10];
[myArray forEachElementWithBlock:^(int idx) {
points[idx] = CGPointMake(10, 20); // error here
// Cannot refer to declaration with an array type inside block
}];
after searching a while found this possible solution, to put it in a struct:
__block struct {
CGPoint points[100];
} pointStruct;
[myArray forEachElementWithBlock:^(int idx) {
pointStruct.points[idx] = CGPointMake(10, 20);
}];
this would work but there is a little limitation I have to create the c array dynamically:
int count = [str countOccurencesOfString:#";"];
__block struct {
CGPoint points[count]; // error here
// Fields must have a constant size: 'variable length array in structure' extension will never be supported
} pointStruct;
How can I access my CGPoint array within a block?
OR
Is it even possible at all or do I have to rewrite the block method to get the full functionality?
Another simple answer which works for me is the following:
CGPoint points[10], *pointsPtr;
pointsPtr = points;
[myArray forEachElementWithBlock:^(int idx) {
pointsPtr[idx] = CGPointMake(10, 20);
}];
Maybe you can allocate the array on the heap?
// Allocates a plain C array on the heap. The array will have
// [myArray count] items, each sized to fit a CGPoint.
CGPoint *points = calloc([myArray count], sizeof(CGPoint));
// Make sure the allocation succeded, you might want to insert
// some more graceful error handling here.
NSParameterAssert(points != NULL);
// Loop over myArray, doing whatever you want
[myArray forEachElementWithBlock:^(int idx) {
points[idx] = …;
}];
// Free the memory taken by the C array. Of course you might
// want to do something else with the array, otherwise this
// excercise does not make much sense :)
free(points), points = NULL;