-(xFuncTest)funcX {
int __block inner = 0;
xFuncTest blockTest = ^(int mark) {
return inner += mark;
};
return blockTest;
}
xFuncTest func = [self funcX];
NSLog(#"%d",func(1));
NSLog(#"%d",func(1));
NSLog(#"%d",func(1));
the result is 1 , 2, 3. but I am confused. because every time the method run. inner has been stetted to 1. why it will remember last value?
Here is your code with a bit more detail.
#import "Block.h"
typedef int ( ^ xFuncTest )( int );
#implementation Block
- ( xFuncTest ) funcX
{
int __block inner = 0;
xFuncTest blockTest = ^ ( int mark )
{
NSLog ( #"\tInside block, inner is %p value %d", & inner, inner );
NSLog ( #"\t\tWill add %d to it", mark );
return inner += mark;
};
return blockTest;
}
- ( void ) test
{
xFuncTest func = [self funcX];
for ( int arg = 1; arg < 5; arg ++ )
{
NSLog ( #"Calling %p with arg %d", func, arg );
NSLog ( #"Result %d", func ( arg ) );
NSLog ( #"\n" );
}
// This resets it - when you create a new block
func = [self funcX];
NSLog ( #"Now I have a new block %p, calling it with arg 20", func );
func ( 20 );
}
#end
Note specifically that each time the block is called I print out the address (and value) of the inner integer. I also print out the address of the block.
Also note that later on I create a new block. This will reset the inner int, in fact, it creates a totally new one as the output will show.
Now calling that test function produces the following output.
2020-10-27 12:52:30.397754+0200 BlockIllustration[1536:55881] Hello, World!
2020-10-27 12:52:30.398181+0200 BlockIllustration[1536:55881] Calling 0x100406350 with arg 1
2020-10-27 12:52:30.398218+0200 BlockIllustration[1536:55881] Inside block, inner is 0x1004063d8 value 0
2020-10-27 12:52:30.398244+0200 BlockIllustration[1536:55881] Will add 1 to it
2020-10-27 12:52:30.398266+0200 BlockIllustration[1536:55881] Result 1
2020-10-27 12:52:30.398286+0200 BlockIllustration[1536:55881]
2020-10-27 12:52:30.398308+0200 BlockIllustration[1536:55881] Calling 0x100406350 with arg 2
2020-10-27 12:52:30.398329+0200 BlockIllustration[1536:55881] Inside block, inner is 0x1004063d8 value 1
2020-10-27 12:52:30.398350+0200 BlockIllustration[1536:55881] Will add 2 to it
2020-10-27 12:52:30.398416+0200 BlockIllustration[1536:55881] Result 3
2020-10-27 12:52:30.398481+0200 BlockIllustration[1536:55881]
2020-10-27 12:52:30.398530+0200 BlockIllustration[1536:55881] Calling 0x100406350 with arg 3
2020-10-27 12:52:30.398556+0200 BlockIllustration[1536:55881] Inside block, inner is 0x1004063d8 value 3
2020-10-27 12:52:30.398578+0200 BlockIllustration[1536:55881] Will add 3 to it
2020-10-27 12:52:30.398620+0200 BlockIllustration[1536:55881] Result 6
2020-10-27 12:52:30.398642+0200 BlockIllustration[1536:55881]
2020-10-27 12:52:30.398689+0200 BlockIllustration[1536:55881] Calling 0x100406350 with arg 4
2020-10-27 12:52:30.403090+0200 BlockIllustration[1536:55881] Inside block, inner is 0x1004063d8 value 6
2020-10-27 12:52:30.403127+0200 BlockIllustration[1536:55881] Will add 4 to it
2020-10-27 12:52:30.403150+0200 BlockIllustration[1536:55881] Result 10
2020-10-27 12:52:30.403172+0200 BlockIllustration[1536:55881]
2020-10-27 12:52:30.403235+0200 BlockIllustration[1536:55881] Now I have a new block 0x102804090, calling it with arg 20
2020-10-27 12:52:30.403281+0200 BlockIllustration[1536:55881] Inside block, inner is 0x1028040d8 value 0
2020-10-27 12:52:30.403309+0200 BlockIllustration[1536:55881] Will add 20 to it
Program ended with exit code: 0
Note that the inner integer uses the same address - it is the same and it will stay that way and only go away when the block itself goes out of scope. This is because it was marked as a __block variable and is tied to that block.
However, whenever you create a new block you also get a new inner integer together with it. This what the latter part of the test tries to illustrate.
HIH
Related
I'm using lldb to debug objc based service. several breakpoints (which is set
have been placed in the code, and I see that one of them is reached unexpectedly according to the stack trace.
The method encapsulating this breakpoint shouldn't have called but I still see it in stack trace (file1.mm:97) although it seems like the code isn't being execute there.
I suspect that objc internal method __Block_byref_object_copy_ is responsible for copying the block of code which involves both caller and callee methods (MyClass from the upper frame in the stack and the method in file1.mm:97).
While copying the debugger probably thinks that it reach this line for execution and stop there, where in fact it's only for copying the code block which involves those 2 methods.
Perhaps anybody can support this claim or provide additional explanation of why am I getting this breakpoint where it shouldn't occur ?
* frame #0: 0x0000000107e03ce0 MyLib`::__Block_byref_object_copy_((null)=0x00007fda19a86b30, (null)=0x00007ffeea7f3bd0) at file1.mm:97:27
frame #1: 0x00007fff7de6bb78 libsystem_blocks.dylib`_Block_object_assign + 325
frame #2: 0x0000000107dd960a MyLib`::__copy_helper_block_ea8_32r((null)=0x00007fda19a86540, (null)=0x00007ffeea7f3ba8) at file2.mm:47:55
frame #3: 0x00007fff7de6b9f3 libsystem_blocks.dylib`_Block_copy + 104
frame #4: 0x00007fff7c64e1e8 libobjc.A.dylib`objc_setProperty_atomic_copy + 53
frame #5: 0x00007fff5411d16b Foundation`-[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:] + 1885
frame #6: 0x00007fff54168508 Foundation`-[NSXPCConnection _sendSelector:withProxy:arg1:arg2:] + 125
frame #7: 0x00007fff54168485 Foundation`_NSXPCDistantObjectSimpleMessageSend2 + 46
frame #8: 0x0000000107e0520e MyLib`::-[MyClass func:withVar0:Var1:Var2:withError:](self=0x00007fda17c2cb50, _cmd="funcWithVar0:Var1:Var2:Var3:withError:", var0="aaa", var1=0x0000000000000000, var2="bbb", var3=0x00007fda17d41dd0, err=0x00007ffeea7f4258) at MyClass.mm:196:5
UPDATE:
thanks to the comments below, it happen that if I set breakpoint according to file and line, it gives me 3 locations (!?)
breakpoint set --file myfile.mm --line 97
now when I list my breakpoints, it give me 2 breakpoints that aren't related to the actual method which wraps the file, besides the expected breakpoint.
3.2: where = my class`::__Block_byref_object_copy_() + 16 at myfile:97:27, address = 0x0000000107e03ce0, unresolved, hit count = 0
3.3: where = myclass `::__Block_byref_object_dispose_() + 16 at myfile:97:27, address = 0x0000000107e03d40, unresolved, hit count = 0
Not really an answer, more an illustration ...
unsigned fn ( void )
{
return 3; // Set bp here and see what happens
}
int main(int argc, const char * argv[])
{
#autoreleasepool
{
// insert code here...
NSLog(#"Hello, World!");
unsigned int x = 0;
x = 1;
x = 2;
x = 3;
if ( x >= 0 )
{
switch ( 5 )
{
case 1 : x = 4; break;
case 2 : x = 4; break; // Set bp here - it will trigger!!!!
case 3 : x = 4; break;
case 4 : x = 4; break;
case 5 : x = 4; break; // Set bp here and see what happens
case 6 : x = 4; break;
case 7 : x = 4; break;
default : x = 4; break;
}
}
__block unsigned y;
void ( ^ b1 )( void ) = ^ {
y = fn();
};
void ( ^ b2 )( void ) = ^ {
b1();
};
if ( YES )
{
b2();
}
NSLog ( #"x = %u y = %u", x, y );
}
return 0;
}
Without going into too much detail, note that most of the code above will be optimised away. The compiler will optimise for loops and switches aggressively and will optimise superfluous assignments and checks (e.g. x >= 0 for unsigned x) away. Above even the blocks gets inlined and you end up with what appears to be very strange behaviour. I think the blocks here are relevant to your specific problem?
If you optimise then the first breakpoint indicated in the code does not get triggered as the blocks all get inlined (I think as I did not look at the disassembly). Likewise the third one does get triggered, but because of optimisation in the strangest of places. Really, a large part of the code gets reduced into a single assignment and the compiler does not really know where to stick it so when that bp is triggered it looks as if it is in the strangest and most disconnected place possible.
Finally, even the second (!!!) one will trigger. That code should never execute but since it all collapse due to optimisation you can even get it to trigger.
So I would not be too perplexed about what triggers your bp ...
I mean, above I just proved that 2 == 5 if I take the bp seriously. And that is not even variable but constant 2 == 5!!! Quite amusing ...
Why are version 1,2 and 3 working, but version 4 fails with: Null regex not allowed when using // over multiple lines?
#1
say Nil //
try {'a'++} //
1;
#2
say Nil
// try {'a'++} //
2;
#3
say Nil
// 3;
#Fails with: Null regex not allowed
say Nil
// try {'a'++}
// 4;
There is try block at the end of a line.
It is same as
say Nil
// try {'a'++};
// 4;
See documentation:
It is OK to skip the semicolon between the last statement in a block and the closing }.
You can try
say Nil
// try {'a'++}\
// 4;
or
say Nil
// (try {'a'++})
// 4;
Is there a way to write a block ( which does not get any parameters) which does something only at the first call.
I want to initialize a local block variable only at the first time and then change its value each time the user call that block by : Block value.
My block will be defined in a method A inside a class B.
and the method returns the block.
so each time I call method A it should do the initialization. but every time I call the block it should continue from the same point.
for example: I want i to be initialized to 0.
A
^[i:=i+1]
ob1 = B new.
res= obj1 A.
Transcript show: res value. // should print 1
Transcript show: res value. // should print 2
res2= obj1 A.
Transcript show: res2 value. // should print 1
Here's your modified code snippet.
A
| first |
first := true.
^[first ifTrue: [i := 0. first := false].
i := i+1]
or more simply:
A
| i |
i := 0.
^[i := i+1]
Technically the second example initializes the variable before the block is even executed. If that's ok, then this works. If you really want the variable initialized on first call, use the first example.
You can use the outer context of the block to do that:
MyClass>>myBlock
| init |
init := false.
^ [init
ifTrue: [1]
ifFalse: [
init := true.
2]].
This gives different results for the first and the second time the block is accessed:
| block |
block := MyClass new myBlock
{ block value . block value } "=> #( 2 1 )"
I'm reading a book to learn Objective-C and this program is suppose to show key concepts in dealing with pointers, and I'm really lost.
Is there some kind of conversion happening in the function's arguments that turn p1, p2, &il, and &i2 to the value (*) of a pointer? Like p1 turns into *p1?
I thought a copy of the variable was passed into the function instead of the actual variable, so why was the value of the passed in variable changed after the function?
Also why am I getting a warning on the 3rd line that says: No previous prototype for function 'exchangeValues'?
Thank you!!
#import <Foundation/Foundation.h>
void exchangeValues (int *pint1, int *pint2) {
int temp;
temp = *pint1;
*pint1 = *pint2;
*pint2 = temp;
}
int main (int argc, char *argv[]) {
#autoreleasepool {
void exchangeValues (int *pint1, int *pint2);
int il = -5, i2 = 66, *p1 = &il, *p2 = &i2;
NSLog(#"il = %i, i2 = %i", il, i2);
exchangeValues(p1, p2);
NSLog(#"il = %i, i2 = %i", il, i2);
exchangeValues(&il, &i2);
NSLog(#"il = %i, i2 = %i", il, i2);
}
return 0;
}
Output:
2012-08-02 11:13:38.569 Test[381:707] il = -5, i2 = 66
2012-08-02 11:13:38.571 Test[381:707] il = 66, i2 = -5
2012-08-02 11:13:38.572 Test[381:707] il = -5, i2 = 66
I would say that's a complex example if you are being taught about pointers!
Is there some kind of conversion happening in the function's arguments
that turn p1, p2, &il, and &i2 to the value (*) of a pointer? Like p1
turns into *p1?
p1 and p2 are declared as int * (pointer to int) and are initialised with the address of i1 and i2 (using the & operator).
I thought a copy of the variable was passed into the function instead
of the actual variable, so why was the value of the passed in variable
changed after the function?
A copy of the variable is passed to the function, however in this case the variable of type int * (pointer to int). The reason the value is changing is because the exchangeValues() function is dereferencing those pointers and swapping the values. This is the only way (in C/Objective-C) a function can modify a variable outside of its own scope, other than the variable being assigned as the return value from a function.
Also why am I getting a warning on the 3rd line that says: No previous
prototype for function 'exchangeValues'?
You seem to have typed it in wrong; remove the line below #autoreleasepool:
#autoreleasepool {
void exchangeValues (int *pint1, int *pint2); <-- delete this line
If you pass a pointer into the function, it indeed passes a copy of that pointer- but it still refers to the same address in memory. So de-referencing that pointer will still point to a variable that's outside of the function scope.
I thought a copy of the variable was passed into the function instead of the actual variable, so why was the value of the passed in variable changed after the function?
A copy of the pointer is passed to the function here. So what the function has points to the memory locations the variables l1 and l2 are stored at. So
void exchangeValues (int *pint1, int *pint2) {
int temp;
temp = *pint1; // store the value that pint1 points to in temp
*pint1 = *pint2; // store the value pint2 points to where pint1 points to
*pint2 = temp; // store the value saved in temp where pint2 points to
}
its a little confusing how the variables have been declared and initialised all in a row like that but basically you have:
i1 is an int set to -5
p1 is a pointer to an int set to the address of i1
same goes for i2 and p2
No conversion is taking place. You're effectively 'swapping' the values that those pointers point to in the function.
Pointers are confusing things but stick with it and it will become clear with enough parctice and example code like this...
Why does
switch ([document currentTool]) {
case DrawLine:
NSBezierPath * testPath = [[NSBezierPath alloc]init];
//...rest of code that uses testPath....
result in
error:syntax error before "*" token
for testPath?
You can't instantiate an object inside a case statement unless you put it inside a new scope. This is because otherwise you could do something like this:
switch( ... ) {
case A:
MyClass obj( constructor stuff );
// more stuff
// fall through to next case
case B:
// what is the value of obj here? The constructor was never called
...
}
If you want the object to last for the duration of the case, you can do this:
switch( ... ) {
case A: {
MyClass obj( constructor stuff );
// more stuff
// fall through to next case
}
case B:
// obj does not exist here
...
}
This is the same in Objective C as well as C and C++.