What exactly does this error message mean and how do I fix it?
Dereference of Null Pointer
It means that self could be made nil by the return value of initWithStyle:reuseIdentifier: and subsequent access to defaults would try to read (hence dereference) at a nil address certainly crashing the app.
Related
Uncaught Kotlin exception: kotlin.ClassCastException: kotlin.UInt cannot be cast to kotlinx.cinterop.CValuesRef
Using below code in Kotlin Multiplatform for SSL pinning for iOS.
SecTrustEvaluate(serverTrust!!, result as CValuesRef)
One cannot cast the value to the pointer type. You got to allocate native memory, put the value into it, and then pass the pointer to this memory into the function. It the end, it has to look somehow like:
memScoped{
val nativeResult = alloc<SecTrustResultTypeVar>()
nativeResult.value = result
SecTrustEvaluate(serverTrust!!, nativeResult.ptr)
}
Here I allocated memory in the memScoped block, so it will be free'd automatically when the block finishes. Please try this approach and tell if something will go wrong, ok?
When a method returns a BOOL and Error at the same time, Is it enough to check for BOOL status or should we add the additional condition for Error as well?
For example, Following method returns a BOOL and error if any.
-(BOOL)canEvaluatePolicy:(LAPolicy)policy error:(NSError * __autoreleasing *)error;
Now should I write
BOOL biometricsAvailable = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
available = (error == nil && biometricsAvailable);
or
BOOL biometricsAvailable = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
is enough?
It is clearly described in the documentation here; https://developer.apple.com/library/prerelease/ios/documentation/LocalAuthentication/Reference/LAContext_Class/index.html#//apple_ref/occ/instm/LAContext/canEvaluatePolicy:error:,
Return Value
true if the policy can be evaluated, false otherwise.
Parameters
policy
The policy to evaluate.
error
On input, a pointer to an error object. If an error occurs, this pointer is set to an actual error object containing the error information. You may specify nil for this parameter if you do not want the error information.
So, this means that the Boolean return value tells you if the evaluation was successful. And in case that fails, your error object will be set, which will have a description about the failure.
No, checking the return value should be enough. But when NO is returned, you can have a look at the error variable to see why.
Apple have stated that you should check the return value of the method and only when this is NO or nil can you check the error,
since the SDK could put some weird value in the error variable.
See the document Programming with Objective-C - Dealing with Errors
Define "enough". For what?
The contract of the convention is that if there is a problem, NO should be returned and if you passed in an NSError pointer it'll be populated. If you want to do something with the error, you have to check it, but the convention says that there'll never be a case where the error is provided but YES is returned (if YES is returned the pointer shouldn't even be touched), or where NO is returned and there's no error. This convention is everywhere in Cocoa and has been stable for decades, and since Swift just based their error handling on this model, I think this is even less likely to change.
Both cases are different. It Depends on your requirement.
If you use only BOOL then you only get the status of the request. Whether it is failed or succeed and based on that you can perform task.But you won't be able to know what is the error.
To know what exactly the error is you should go with with first method. If you want to know.
my app has been crashing on releasing values pulled from an address book that turned out to be null
Is it okay to only release if the value is not null or do you always have to release?
CFStringRef firstName = ABRecordCopyValue(lRef,kABPersonFirstNameProperty);
// CFRelease(firstName);// this was causing crash
if(firstName!=NULL) {
CFRelease(firstName);
}
Newb to core foundation so appreciate guidance.
If the argument is NULL, CFRelease will cause a runtime error and your application will crash.
If the retain count of CFTypeRef objects becomes zero the memory allocated to the object is deallocated and the object is destroyed. If you create, copy, or explicitly retain (see the CFRetain function) a Core Foundation object, you are responsible for releasing it when you no longer need it.
so yes, you should only call CFRelease if firstName is not NULL when you no longer need it.
What is the safe way to compare to NSNumbers? If I do isEqualToNumber: and one of the numbers is nil, I still get an
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber compare:]: nil argument'
I thought nil defaulted to zero in iOS? Please help me understand some fundamentals if possible. Thanks.
my code is
numberB=[numberB isKindOfClass:[NSNull class]]?0: numberB;
if([numberA isEqualToNumber: numberB]){...}
It seems that the NSNull check is ignored because my logging shows that numberB is still (null) instead of 0. I am really trying, here. So thanks for any help.
If the argument might be nil, use isEqual:, not isEqualToNumber:. The isEqual: method is documented to accept a nil argument.
What defaults to nil (or a zero-like quantity) in Objective-C is the return value of a message when you send the message to nil. For example, [nil isEqualToNumber:#7] returns NO; [nil copy] returns nil; [nil integerValue] returns 0. Thus it is generally safe to send any message to nil. It is not necessarily safe to pass nil as an argument to a message if the message isn't documented to accept nil as an argument.
UPDATE
Based on the code you added, you could do this:
numberB = (numberB == [NSNull null]) ? #0 : numberB;
if ([numberA isEqualToNumber:numberB]) {
...
}
Note that #0 represents an NSNumber with value 0. Also, there is only one instance of NSNull, so you can check for it with ==.
UPDATE 2
If NSLog is printing (null), then numberB is nil, which is different that [NSNull null]. You can check for both possibilities like this:
numberB = (numberB == nil || numberB == [NSNull null]) ? #0 : numberB;
if ([numberA isEqualToNumber:numberB]) {
...
}
If you are just worried that numberB could be nil and want to ignore that case:
if([numberA isEqualToNumber:numberB?: #(NSIntegerMax)]){...};
Note that this will also ignore any case where numberA is nil.
NSLog for numberB is null cause numberB is nil.
Make a test:
NSLog(#"NumberB is nil? %#", numberB == nil ? #"YES":#"NO"); --> displays 'NumberB is nil? YES'
when you compare a nil to [NSNull null], it returns NO
I suppose that you get numberB from a code like:
NSNumber *numberB = (NSNumber*)[[NSUserDefaults standardUserDefaults] valueForKey:#"numberB"];
it returns 'nil' value.
you should then compare numberB to nil, but not to [NSNull null].
Example
numberB = numberB != nil? numberB : #0;
if ([numberA isEqualToNumber:numberB) {
...
}
Nil defaults to zero (or the boolean NO) in logical statements. So for example if(nilObject) will evaluate to false. Nil arguments by default do not evaluate as 0. It's up to the specific method's implementation.
In this case, NSNumber compare: expects the argument to be non-nil. It's not a universal rule in Objective-C, just an NSNumber implementation detail.
You could first convert your NSNumber objects into primitive types, e.g. by calling [myNumber doubleValue] and then compare those. By the way, getting the primitive value from a nil NSNumber will give you 0.
I finally got it to work by doing
numberB= (numberB == nil)?[NSNumber numberWithLongLong:0]:numberB;
So the problem seems that #0 or simple 0 was being converted to nil. I don't quite understand it, but now it works. Thanks and +1 for everyone for all the help.
While the other answers are correct, let me add some more basic explanation:
In programming we're dealing with values and pointers. A value is a piece of data such as a numeric value or a string of characters. A pointer is a value too, but a specialized one - it is the address of a value in memory. Hence the name - it points to a piece of usable data.
If you do something like NSNumber *happyNumber = #7;, happyNumber is a pointer and it points to the value 7. Well, not exactly, because your 7 is actually wrapped in an object, but that's another story.
Now, sometimes a pointer is still around while the value it pointed to became invalid or is about to. Or the value doesn't even exist yet. But a pointer can never be "empty" and will always point at some memory address, so using such a pointer may result in undefined and random behavior. And to prevent this, we're using nil to give the pointer something meaningful to point to. It is sort of a placeholder, representing the "empty" state for a pointer and at the same time makes accidential use of the pointer relatively safe.
This means that you can throw messages at a nil object and quite literally, nothing happens. If you feed a nil pointer or object to another object though, it might not be prepared or able to handle "emptiness". This is what happened with isEqualToNumber:: it makes no sense to compare two numbers if one isn't even a number. In this case even just returning a boolean NO would be wrong in a way too, because it would imply that we are dealing with two perfectly healthy numbers which just happen to be different. So instead, NSNumber resolves the situation by throwing an exception.
NSNull is similar to nil in that it represents absence of something useful, however it is not the same. NSNull is a class and you can get a (singleton) instance of it. It is used where the absence of something needs to be represented by an actual, live object.
That's why the first version of your ternary operation failed - numberB was nil, not [NSNull null] so you where just checking for the wrong type of "emptiness" (#0 results in a perfectly fine NSNumber, not nil).
You can of course check for both possibilities, but if you default on using nil for yourself (which you should) this will seldom be necessary.
Hope that helps. Cheers!
Let's say a method returns a CFErrorRef via a pointer. This returned error may be NULL. So would it be safe to perform a __bridge_transfer still or should I check for NULL.
E.g.
CFErrorRef cfError;
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &cfError);
NSError *error = (__bridge_transfer NSError *)cfError;
I don't see any mention of this in the documentation and CFRelease documentation specifically states This value must not be NULL.
https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFTypeRef/Reference/reference.html#//apple_ref/c/func/CFRelease
You do not need to check for NULL.
ARC is a strictly compile-time mechanism. When you use __bridge_transfer you are merely transferring memory management responsibility of a variable to the compiler. Whether cfError happens to be NULL or not at runtime is completely irrelevant to the compiler.
In your case, ARC will insert a release for error, but if error happens to be nil it's a simple no-op.
The error will be non NULL if the return value of the function is NULL.
The pattern for this kind of CF function is to wrap the error checking in an if statement.
if (addressBookRef == NULL) { /* your error handling here */}
You should not try to bridge anything unless it is non NULL. Object ownership or more accurately retain count and responsibility for decrementing it, are not meaningful with NULL or nil. It would be an anti pattern.
At best it's a null operation.
Sending messages to nil with Objective-C is fine, including retain and release.
It is not fine to pass a NULL value to CFRelease() or CGRetain()
The direct answer to the question is yes, you can use __bridge_transfer on NULL. But this isn't the right question.
Read the documentation on ABAddressBookCreateWithOptions. In particular, check out the documentation for error:
On error, contains error information. See “Address Book Errors.”
This is important.
error's value in the case of success is not documented.
error being nil/NULL/0 (ever) is not documented.
This isn't academic. Some APIs have historically set error to invalid values. Imagine the call set the CFError to -1. That's "valid" since the non-NULL reply means you're not supposed to interpret the error, but bridge casting -1 to a NSError will probably crash.
That means you must not touch cfError unless an error is indicated by ABAddressBookCreateWithOptions returning NULL.
CFErrorRef cfError;
NSError *error;
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &cfError);
if (addressBookRef == NULL) {
error = (__bridge_transfer NSError *)cfError;
}
You didn't ask this, but one additional wrinkle here is that bridges aren't even required if the compiler recognizes that something is 0-equivalent. For instance, this code will compile silently (assuming _thing1 and _thing2 are instance variables):
- (id)bar {
if (_thing1) return NO;
if (_thing2) return 0;
return NULL;
}
This is sloppy code, and I you should not do this intentionally, but knowing it builds cleanly… it's a good thing to look for. I ran into a bug caused by something like this:
- (NSNumber *)someCalculationWithError:(NSError *)error {
return 0; // meant to return #(0)
}
Unlike NSObjects, sending messages to NULL CF objects is not ok. I don't know about bridging casts specifically, but I would guess that no, casting a CF object to an NSObject using __bridge_transfer is NOT ok.
Why not try it and see? Cast it to a variable in the local scope of an instance method. That way, as soon as the method goes out of scope the system should try to release the object.