Why is a ObjC 'NSString * _Nullable' is transformed to a 'String!' property in Swift - objective-c

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

Related

Objective-C Nullability: Qualifying Constant Strings

I have gotten into a pretty good habit of declaring and using constant strings for things like NSNotification names. I declare them like so:
extern NSString * const ABCAwesomeThingHappenedNotification;
With the introduction of Xcode 6.3 and Swift 1.2, I'm going back and auditing Objective-C classes that interop with Swift using the new nonnull, nullable, and null_unspecified qualifiers.
When adding the qualifiers to a header that also has externally visible static strings, I receive the following warning:
warning: pointer is missing a nullability type specifier (__nonnull or __nullable)
Hmm. That's confusing / interesting. Can someone explain the reasoning behind this message? When using ABCAwesomeThingHappenedNotification in Swift, it never suggests that it's an optional String or implicitly unwrapped String.
I agree that having this specifier shouldn't be required but here is syntax
extern NSString * const MyConstant;
extern NSString * __nonnull const MyConstant;
In your implementation, you could define:
NSString * const ABCAwesomeThingHappenedNotification = #"ABCAwesomeThingHappenedNotification";
in which case the pointer is clearly nonnull. However, this is also valid:
NSString * const ABCAwesomeThingHappenedNotification = nil;
which must be considered nullable because the pointer is always a null pointer.
(The explicit initialisation to nil is redundant since this happens implicitly if no initial value is provided, but clarifies this example.)

What do the null-related property attributes in Xcode do?

With Xcode 6.3 I noticed some property attributes, namely:
nonnull
null_resettable
nullable
Could someone explain what they do when applied?
Apple has added two new type annotations:
A__nullable pointer may have a nil value,
while a __nonnull cannot have a nil value
As you should know in Swift you can use Ottionals, but in Objective-C you cannot. Those attributes let you create Objective-C code which is more understandable by Swift and compiler warn you when you break the rule, for example:
#property (copy, nullable) NSString *name;
#property (copy, nonnull) NSArray *allItems;
This will be 'translated' in swift to:
var name: String?
var allItems: [AnyObject]!
This is taken from NSHipster:
nonnull: Indicates that the pointer should/will never be nil. Pointers
annotated with nonnull are imported into Swift as their non-optional
base value (i.e., NSData).
nullable: Indicates that the pointer can be nil in general practice.
Imported into Swift as an optional value (NSURL?).
null_unspecified: Continues the current functionality of
importing into Swift as an implicitly unwrapped optional, ideally to
be used during this annotation process only.
null_resettable:
Indicates that while a property will always have a value, it can be
reset by assigning nil. Properties with a non-nil default value can be
annotated this way, like tintColor. Imported into Swift as a
(relatively safe) implicitly unwrapped optional. Document accordingly!

How to declare a double pointer property in Objective-C?

I have a function declared like this:
- (void)loadWithCompletion:(MyCompletion)completion error:(NSError**)error;
The function takes a double pointer to an NSError so I can report errors to the caller. The completion (and possibly the error) will occur some time after the function is called. I need to store the NSError** as a property so I can use it when the aforementioned time passes.
#property(nonatomic, assign) NSError** error;
This property declaration gives me the error:
Pointer to non-const type NSError* with no explicit ownership.
add __autoreleasing between the **, to give NSError*__autoreleasing* error
In Xcode 5.1 the ARC warning "Implicit ownership types on out parameters" was turned on by default (it used to be off). So with 5.1 this warning started appearing when there was no specified ownership.
The compiler assumes you want autoreleased, which is usually correct, but it's better that the author think about it and specify what the really want.
Usually you want the output parameter to be autoreleasing, similar to a function result. The caller will get an autoreleased object and will need to store it in a strong variable if they want to retain ownership.

Why isn't there a 'nonnil' attribute for clang?

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

Makes pointer from integer without a cast warning in singleton int

Objective-C, xCode for iOS
In a class, I want to assign a singleton integer's value. Right now I have:
[ExGlobal sharedMySingleton].tetraCountEx = tetraCount;
I've got this warning before, and have been able to resolve it, but this seems like I would have to do something different by letting the compiler know that tetraCountEx is an integer. I just don't know how.
That error is a result of trying to store a number as a pointer. With out you posting any code as to how tetraCountEX is declared I can only guess what your problem is.
On reason may be that tetraCountEx is defined as an NSNumber and if that is the case use
[ExGlobal sharedMySingleton].tetraCountEx = [NSNumber numberWithInt:tetraCount];
//or numberWithInteger: or the appropriate type
And the other reason may be accidentally declaring tetraCountEx as a pointer
//Remove the * if this is the case
#property(nonatomic, assign) int *tetraCountEx;