Does anyone know why I am getting the following error:
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath;
{
id result = (Possession *)[possessions objectAtIndex:[indexPath row]];
[result setRowSwapped:TRUE]; //Passing argument makes pointer from integer without a cast
}
//This is the property on the possession object. I just want to set it as true thats it
#property (nonatomic) bool *rowSwapped;
TRUE is a number (equaling 1 in value) and setRowSwapped seems to expect a pointer of some kind as argument. Thus the compiler is transforming the int value 1 into a pointer, which is a warning, because this is hardly ever correct and if it was correct and you'd know what you are doing, you had used an explicit cast, which also avoids the warning. Sine you used no cast, you probably expected that the method expects a boolean as argument, and that seems to be incorrect.
BTW, since this is Objective-C, you should not use TRUE/FALSE in Objective-C, but YES/NO. The difference is that TRUE/FALSE is of type bool (all lower case, same as _Bool or boolean_t on Mac) and that again is usually of type int and 4 byte (at least on PPC and Intel, maybe not true for other Apple devices, like iPad). YES and NO are of type BOOL (all upper case) and this type is 4 Byte on PPC and 1 Byte on Intel. Thus bool and BOOL are not always the same and in some very rare conditions this can indeed cause problems. So you should not mix them. In Obj-C code use BOOL and YES/NO, in C code, use bool, boolean_t or _Bool and TRUE/FALSE.
You need to show us the definition of your setRowSwapped: routine to be sure, but it looks to me like you have a mismatch in the definition and the use. Did you make that method take a BOOL * parameter? Regardless, it's a little weird to type your variable id - what is your goal on that front?
I used bool instead of BOOL.
Related
I am new to iOS programming, I am preferring Swift language and I don't know Objective C. While I am wandering through some library, I got a value of type UnsafeMutableRawPointer in swift, that is actually a String value with utf8 encoding.
So I just looked into the corresponding objective c class and the variable is declared as
#property (readonly) void *data;
So why there is void pointer and why it is converted as UnsafeMutableRawPointer?
Consider me as a noob in Objective c or c.
Thanks in advance
This whole thing might be quite a lot for a beginner to understand. So let's start with ObjectiveC syntax:
Property #property (readonly) void *data; exposes interfaces which says there must be a method of type - (void *)data which means an instance method returning a void pointer. A void pointer being a pointer to anything.
ObjectiveC is then kind of a pure C a level deeper. I will not check exact transformation but since C has no methods this is all done with functions or even pointers to functions. So somewhere down there there should be a function (let's say the name of this class is MyDataClass)
void *myDataClass_data(MyDataClass *self) { return self->_data; } // Or whatever the implementation is
So nothing really interesting is going on under the hood. The whole thing just returns a position in memory without any further information of what should be there. You as a developer must know and interpret it. From C (or ObjectiveC) this is very simply. A few examples:
char *aString = (char *)myDataClass.data; // A pure C string. Expected to be null terminated
int *arrayOfIntegers = (int *)myDataClass.data; // An array of integers
int thirdItem = arrayOfIntegers[2];
MyDataClass *nextItem = (MyDataClass *)myDataClass.data; // A pointer to another instance
for(MyDataClass *iterator = myDataClass; iterator != nil; iterator = (MyDataClass *)iterator.data) {}
I hope you get the picture. The point is that C and then also ObjectiveC are very unsafe when it comes to data types. You can basically convert anything into anything however you want it and it will compile. The problem is what will happen in runtime.
When looking at Swift things get much safer and you can not just say something like let integer: Int = myDataClass as Int. You can force cast it and it will crash. Or you can do optional cast and it will return nil.
So once transitioned from C/ObjectiveC you will receive an unsafe mutable raw pointer. That means it got a position in memory witch it has no idea about what it is and how to use it. You may try to convert it to anything you want but it is unsafe as it will ignore all type checking. It is mutable probably because data it holds may be changed at any given time by any system. It is raw as it holds no additional information (like it's a string). And it's a pointer because it only points to a position in memory.
(All the snippets are symbolical to explain what goes on under the hood. Please do not take them literal)
After this somehow related question Why can't I pass an UninterpretedBytes to a void* thru DLL/C-Connect? where we saw that I could not pass a Smalltalk array of bits to a void * parameter, I further analyzed the method responsible for checking the compatibility of formal pointer description with effective object passed as argument, and I think that I discovered another questionable piece:
CPointerType>>coerceForArgument: anObject
...snip...
(anObject isKindOf: self defaultDatumClass)
ifTrue: [
(referentType = anObject type referentType
or: [(referentType isVoid
and: [anObject type referentType isConstant not])
or: [anObject type isArray not
or: [anObject type baseArrayType = referentType]]])
ifTrue: [^anObject asPointer]].
...snip...
It means the following:
It first checks if the argument is CDatum (a proxy to some C-formatted rawdata and associated CType).
If so, it checks whether the type is the same as the formal definition in external method prototype (self).
If not, it could be that the argument is void *, in which case any kind of pointer is accepted (it has been checked that it is a pointer in the code that I snipped), except if it is pointer on a const thing.
There is a first discrepancy: it should check if the formal definition is const void * and accept any pointer on const in this case... But that does not matter much, we rarely have actual argument declared const.
If not, it checks if either not an array (for example, int foo[2]), or an array whose type matches (same base type and dimension).
So, if the formal definition is for example struct {int a; char *b} *foo, and that I pass a double * bar, the type does not match, there is no const qualifier mismatch, and the parameter is not an array, conclusion: we can safely pass it without any further checking!
That's a kind of pointer aliasing. We do not have an optimizing compiler making any speculation about the absence of such aliasing in Smalltalk, so that won't be the source of undefined behaviour. It could be that we deliberately want to force this sort of dirty reinterpret_cast for obscure reasons (since we can explicitly cast a CDatum, I would prefer the explicit way).
BUT, it might be that we completely messed up and passed the wrong object, with wrong type, wrong dimension, and that the address foo->b in my example above will contain either some re-interpreted garbage if pointer is 32bits aligned, or be completely undefined on 64 bits machine (because beyond the sizeof double).
A C compiler would warn me for sure about the aliasing, and prevent production of artifact with -Wall -Werror.
What troubles me here is that I do not even get a warning...
Does it sound correct?
Short answer: it's not OK to correct this behavior, because some low level user interface stuff depends on it (event loop). We can't even introduce a Warning or anything.
Longer story: I tried to rewrite the whole method with double dispatching (ask anObject if compatible with formal CPointerType rather than testing every possible Object class with repeated isKindOf: ).
But when ommitting the disgracious pointer aliasing tolerance, it invariably screw my Macosx 8.3 image with tons of blank windows opening, and blocked uninterruptable UI...
After instrumenting, it appears that the event loop relies on it, and pass aString asNSString (which is transformed into utf16, but stored into a ByteArray and thus declared unsigned char *), to an Objective C method expecting an unsigned short *.
It's a case where the pointer aliasing is benign, as long as we pass the good bytes.
If I try and fix asNSString with a proper cast to unsigned short *, then the UI blocks (I don't know why, but it would require debugging at VM level).
Conclusion: it's true that some distinction such as (unsigned char *) vs (char *) can be germane and should better not be completely prohibited (whether char is signed or not is platform dependent, and not all libraries have cleanly defined APIs). Same goes with platform dependent wide character, we have conversion methods producing the good bytes, but not the good types. We could eventually make an exception for char * like we did for void * (before void * was introduced, char * was the way to do it anyway)... Right now, I have no good solution for this because of the event loop.
I know this could be a dumb question.
I am totally confused about this, i accept i have not understood the basics properly. Why did
BOOL *booleanTest = (5 < 1)? YES : NO;
did not throw a compilation error, it is a primitive datatype and it cannot have pointer, what made it to compile and return yes always, irrespective of condition inside.
Please bless me with the reason and also why
int *magicNumber = value / 25;
did not throw a compilation error.
C is not as strictly typed as you apparently believe. Assigning an integer to a pointer is legal, though usually unwise. The compiler should have warned you that the assignment makes a pointer from an integer without a cast, though.
In both the cases you are declaring the variables and using them there itself without any sort of initialization.
I am assuming that you do not know the difference between declaration and initialization so during declaration the value of the variables is set to garbage or some random value. How that is assigned is because the memory cell that the pointer is pointing to is some random memory cell which was used by some other application which has left the value there.
Now what happens in the first case:
BOOL *booleanTest = (5 < 1)? YES : NO;
The pointer booleanTest is set to type BOOL and the value that it is pointing is only half a number that is required to point to a full memory cell. So it takes up the first few bits of the cell and which is probably 1 so it is coming to YES always.
In the second case
int *magicNumber = value / 25;
This won't cause any compilation error as it is legally allowed to store values inside a pointed value. It gets type casted to the exact variable type of the pointer.
i'm trying to understand this in objective-c :
in this example, indexPath is a pointer but we use it "as is" in the function : indexPath.section, instead of (for example) *indexPath.section(with a *) :
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
return (indexPath.section == 0) ? nil : indexPath;
}
so, in objective-c, we don't need to add a * to get the content of the variable where the pointer points to...?
but i found this function, where they use a * on the pointer inside the function (on reverse ) :
NSInteger lastNameFirstNameSort(id person1, id person2, void *reverse)
{
NSString *name1 = [person1 valueForKey:LAST];
//...
if (*(BOOL *)reverse == YES) {
return 0 - comparison;
}
and for the id variables, they are using the variable name as is : for example here : person1
So, could someone explain me the differences between those 2 examples :
why on the first example, we don't add a * on indexPath,
why we don't add this * on the id variables, and we use it with *reverse in the second example?
Thanks
You are confusing dot-notation with reading a structure. This is not surprising, since Apple made them ambiguous.
indexPath.section does not mean "the section structure element in indexPath. It doesn't even mean "the property section in indexPath." It means [indexPath section]. It just calls the method section and returns the result.
Similarly, foo.bar = baz does not literally mean "set the property bar to baz." It literally means [foo setBar:baz]. Whatever setBar: does will be done. In most cases, it sets an ivar.
Since indexPath is also technically a struct pointer, it is possible in some cases (but not always, and not often if you code correctly) to say indexPath->section. You should never do this. (There are some extremely rare exceptions, but you are unlikely to encounter them.)
The frustrating thing about all of this is that foo.bar might be a structure reference or it might be a method call. Without knowing what foo is, you can't know. This is one of the problems with dot notation.
If you find it confusing, don't use dot notation (it continues to be a controversial feature among experienced developers). It is never required. It's just a shortcut for the more explicit [foo bar] and [foo setBar:baz].
*(BOOL *)result means "cast result from void* to BOOL * and then dereference it as a BOOL. It's unrelated to dot notation.
Dot-syntax on ObjC objects (pointers to objects) is a way of accessing methods of the forms [object getter] and [object setter: value], using java/c#/javascript like notation (object.property) While the syntax isn't exactly consistent, object->property is already taken by direct property access. reverse is just a normal void pointer, and so the (BOOL*) converts it to a BOOL pointer, and the * before it dereferences it. id types are still pointers, it's just that the syntax for property access in ObjC isn't consistent with the existing C syntax.
What is the difference between these two methods that I believe do the same thing (cast to a BOOL):
BOOL boolOne = (BOOL) [dictionary objectForKey:#"boolValue"];
BOOL boolTwo = [[dictionary objectForKey:#"boolValue"] boolValue];
When should either be used over the other?
They are quite different.
The first gets an object pointer from the dictionary, then interprets the pointer as a BOOL. This means that any non-nil pointer will be interpreted as YES, and nil as NO. In the concrete example, as dictionaries cannot contain nil pointers, you will only ever get YES from this line of code.
The second one takes the same object from the dictionary, then sends the message boolValueto that object. Presumably, and if the object recognizes the message, that will result in a BOOL version of the object.
As a concrete example, if the dictionary contains an NSNumber associated with the key #"boolValue", the NSNumber will receive the message boolValue, and if it is non-zero return YES, otherwise NO.
So to answer your question, you should use the second form. Casting a pointer to a BOOL rarely makes any sense.
No, they are not the same. The difference is that 2nd one is correct one, 1st one is not.
In your 1st line you simply cast pointer to BOOL which is roughly equivalent to checking if pointer is nil or not and has nothing to do with the value actually stored in the object.
[[dictionary objectForKey:#"boolValue"] boolValue];
is not a cast, but calls a method on NSNumber, that returns a bool. Inside a cast might be involved — but the implementation details aren't public.