nonnull works for C functions but not obj-c methods. To be clear, I am suggesting this
- (void)doSomethingWithRequiredString:(NSString * __attribute((nonnil)))requiredString
bar:(NSString *)optionalString);
or (more like nonnull)
- (void)doSomethingWithRequiredString:(NSString *)requiredString
bar:(NSString *)optionalString)
__attribute((nonnil(0)));
I have puzzled over whether or not there is a good technical reason. I understand that clang could only really use the attribute for a compile time check or static analysis, but that seems orthogonal. Is there some strong reason not to have this?
You totally can. The only thing you're doing wrong is thinking that method parameters are 0-indexed, when in fact they're 1-indexed (oh, and it's nonnull, not nonnil):
- (void)doSomethingWithRequiredString:(NSString *)requiredString
bar:(NSString *)optionalString
__attribute((nonnull(1)));
Now when you try to use that:
id thing = ...;
[thing doSomethingWithRequiredString:nil bar:#"42"];
Xcode will warn you with a by saying "Null passed to a callee which requires a non-null argument".
Also, if you leave out the "(1)" portion of the __attribute, it's assumed that the non-nil requirement applies to all parameters.
Clang recognizes the GCC attributes, and GCC's definition of the nonnull attribute is here: http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Function-Attributes.html#index-g_t_0040code_007bnonnull_007d-function-attribute-1733
Update: As of Xcode 6.3 a cleaner syntax is supported.
In properties and methods the keywords are nullable, nonnull and null_unspecified.
So your method signature would become this:
- (void)doSomethingWithRequiredString:(nonnull NSString *)requiredString
bar:(nullable NSString *)optionalString;
In the Xcode 6.3 beta new Objective-C features have been added to express (non)nullability in headers: https://developer.apple.com/swift/blog/?id=22
Yes there is.
You may code like this:
- (nullable AAPLListItem *)itemWithName:(nonnull NSString *)name;
- (NSInteger)indexOfItem:(nonnull AAPLListItem *)item;
https://developer.apple.com/swift/blog/?id=25
Related
With code like this:
- (nonnull NSString *)testing {
return nil;
}
Shouldn't I get a compiler warning? I get no warning all, which seems to make the entire nullability stuff seem useless?
Well, in my opinion it should produce a warning, but I couldn't figure out to get one either.
What might be helpful though, is using Product > Analyze to run the CLANG Static Analyzer. This should give the following hint:
Null is returned from a method that is expected to return a non-null value
Another thing worth mentioning is the setting CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION which is named Incorrect Uses of Nullable values in the Apple LLVM 7.1 - Warnings - All languages section of the Build Settings.
This setting will not produce a warning for incorrect return values, but it shows a warning when using the method with incorrect parameters (e.g. nil for nonnull parameters).
This answer refers to Xcode Version 7.3.1 (7D1014)
"nonnull" is mostly there to combine Objective-C and Swift. Swift will translate the type of the method to "NSString" and not "NSString?".
In my Objective C code I have the property:
#property (nonatomic, readonly) NSString * _Nullable myNullableString;
I wanna use it in my Swift code but in this case, Xcode / Sourcekit thinks that myNullableString has not the type String? but has the type String!.
Due to this fact a guarded unwrapping the property is incorrect but also a forced use is incorrect and will lead to a crash of Xcode / SourceKit or to an segfault if I wanna build it.
Any idea how to solve it?
Null is not the same as nil.
A string that is Null is a non initialized string but a string nonetheless while in swift you have something that's called 'optional' that doesn't exist in obj-c.
so String? means that the function will return eaither a full fledged string or nil which is something undefined(not non-initialized).
so in fact the closest thing in swift is String!" which is an
obligatory string(cannot return nil).
edit: As pointed out by Martin in the comments-the first part of the above mentioned statement is incorrect
I'm developing an API using Objective-C, this API has protocol with some fictional method:
- (NSString *)gimmeString; // Want implementations to never return nil
I'm a big fan of providing context, so I heavily use everything for that purpose including attributes like __attribute__((nonnull)) and friends. What I'm asking is if there a way to provide context and possibly add a compile time check for method implementation saying "this method never returns nil" when compiled with clang?
i.e. I'd love to have something like:
#protocol MyProtocol
- (NSString *)gimmeString __attribute__((no_I_never_really_really_return_that_weird_nil));
#end
#implementation MyProtocolAdopter
- (NSString *)gimmeString
{
return nil; // WARNING! You're returning nil, YOU PROMISED!
}
#end
instead of just:
#protocol MyProtocol
// This method should never return nil
- (NSString *)gimmeString;
#end
#implementation MyProtocolAdopter
- (NSString *)gimmeString
{
// muvahaha, I lied!
return nil;
}
#end
I understand it is impossible to fully determine that at compile time, but detecting return nil; or functions which for sure evaluate to nil is fine.
Idea with something like __attribute__((objc_method_family(copy))) seems weird and unacceptable, but I didn't manage to find anything better then just adding a comment leaving my API users in a bit scarier and more unreliable world.
- XCode 6.3 -
Since XCode 6.3 you, actually, can annotate pointers to be nullable and nonnull and get compile time checks.
- (nonnull NSString *)gimmeString;
- Pre XCode 6.3 -
After some research, which included digging into clang and gcc docs I found that there's no way to achieve what I want in Objective-C.
Thoughts why is that so:
I believe that's because there's no way to determine that at compile time at some sophisticated level of quality. You can't tell for sure if method always returns not-nil at compile time. And determining if method could return nil is something shaky, guess, it's possible to evaluate all
return %something_which_evaluates_to_nil_at_compile_time%;
and warn on all methods which depend on that, but, for example, you can't be sure that some -init method does not always return nil or some web request get's you a request without additional context provided everywhere and you'll end up with false-negatives.
Even -dequeueReusableCellWithIdentifier:forIndexPath: from UITableView which guaranties to always return valid cell is defined as just:
- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier
forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
What I've came up with:
So, what I've came up in Objective-C is providing context without compile-time checks. I add comments like that:
#protocol MyProtocol
/**
* Creates and returns a string.
*
* #note Implementations should never return nil.
*
* #return A string, guarantied not to be nil.
*/
- (NSString *)gimmeString;
#end
Also one more thing could be done to make this more readable, we can define an empty define and append it to the end of declaration, like this:
// Marks method to never return nil
#define MD_RETURNS_NONNULL
#protocol MyProtocol
/**
* Creates and returns a string.
*
* #note Implementations should never return nil.
*
* #return A string, guarantied not to be nil.
*/
- (NSString *)gimmeString MD_RETURNS_NONNULL;
#end
So eye catches this line making your code more readable, making your code users happier because they understand what you want to emphasise easier.
Swift
And the last but not the least is suggestion to move to Swift. In Swift this is possible and built in, you just define your method to return not an optional type:
protocol MyProtocol {
func gimmeString -> String
}
And you're good to go.
Conclusion
If you really want checks like this in Objective-C there's no magic, you only do it at the run time, at the same time you could provide context, which is great. But oh, wait, there's also Swift option, we'll anyway migrate to it at some time, so take your time and spend some of it learning this great new language. This need is a great example where Swift's safety features are really suitable.
UPD: Played with OCLint a bit, looks like something like this could be achieved using it (or just writing a custom Clang extension).
Why the compiler gives an error in this case of method declaration -
-(void) someMethod (void);
But approves this -
-(void) someMethod;
(SomeClass.h)
I've read that it is better to declare (void) in parameters than not declaring, but probalby I miss some point.
You cannot do this for Objective-C.
In Objective-C, every parameter must be after : e.g.
- (void)someMethod:(int)i;
- (void)someMethod:(int)i withString:(NSString *)string;
- (void)someMethod:(int)i :(int)i2 :(int)i3; // you can do this but is bad style
and it does not make sense to make something like
- (void)someMethod:(void)what_goes_here;
so if you want a method without parameter:
- (void)someMethod;
However you can do it in C/C++
void someMethod(void);
And I didn't see any benefit of declare void parameters (explicitly declare things is not always good).
Expanding on #xlc's answer
The answer is a difference in syntax between Objective-C and "normal" C/C++.
Way back in the origins of Unix and C days, late 60's/early 70's, when declaring (not defining) a function, you didn't need to specify how many arguments it accepted, or what types they needed to be. Nor did you need to specify whether or not it returned a value.
Later, folks realized that this would be a good idea, both for better error detection at compile time and for greater efficiency of generated code. So implementers added the ability to specify argument types in the function declaration. This was standardized as part of ANSI C in the late 80's.
However, there was a need to retain backwards compatibility with existing code. So a function declaration of foo() couldn't be assumed to mean "function with no arguments". To solve this, the void keyword was introduced. That allowed you to say foo(void) to mean "function named foo which takes no arguments".
When Objective-C was invented in the 90's, they added a new syntax for defining methods. Because there was no legacy code to deal with, they simply said that a method has to declare all its arguments; if there are none, then the method takes no arguments.
Objective-C still uses the void keyword to indicate that a method returns no value, though.
Is there anything like C++s safe casts in Objective-C?
I know that they are in Objective C++, but I am unsure about possible side effects. Using Objective C++ may slow compilation time - are there any other reasons not to use it?
Objective-c does have C++ safe casts. Alternatively, we can use runtime reflection:
id myOb=[someObject getObject];
NSAssert([myOb isKindOfClass:[MyClass class]], #"Return value is not of type MyClass as expected.");
MyClass * newOb= (MyClass *)myOb;
References:
Cocoa with Love:
You can turn on compiler flags to warn you in cases like this. This particular mistake would be caught by the -Wconversion flag.
Which feature of C++ do you think will help you cast a 64-bit long to a 32-bit int?