_Nullable method in Objective-C - ios

If I have a method:
- (NSString*)convertName;
And then I do something like:
- (NSString*)convertName {
if (![myName isEqualToString:#"someString"]) {
return NULL;
}
.......
}
Why the compiler is letting me do this if I didn't specify _Nullable?

In Objective-C, if your methods are either:
Not declared within a NS_ASSUME_NONNULL_BEGIN/NS_ASSUME_NONNULL_END block
Not declared explicitly with _Nullable/_Nonnull parameters/return types
then the compiler will not enforce non-optionality. In this case optionality is implied (which is the opposite of Swift, where optionality must be explicitly stated), but in an unsafe way.
You can see this if your method above is represented in Swift – it would be shown as being declared like so:
func convertName() -> String!

Related

Inconsistency in Swift optional protocol behaviour

Coming from .Net, I am trying to learn Swift3/iOS and got puzzled by the following apparent inconsistent behaviour of optional protocol members. I suspect its something got to do with the juggling between objc/swift words, but what am I missing here actually?
// In playground, given below:
#objc protocol SomePtotocol {
#objc optional func someMethod()
}
class SomeDelegate: NSObject, SomePtotocol {
}
class SomeController: NSObject {
var delegate: SomePtotocol = SomeDelegate()
}
// This works and compiles without error
let controller = SomeController()
controller.delegate.someMethod?() // No error, typed as '(() -> ())?'
// But this fails to even compile ??
let delegate = SomeDelegate()
delegate.someMethod?() // Error: 'SomeDelegate' has no member 'someMethod'
I would expect either both to fail or both pass, so if someone could please enlighten me on this anomaly.
The difference between the two blocks of code is the type of the variable involved.
In the first block, delegate is explicitly typed as SomePtotocol, and this protocol defines the someMethod method, so your statement is valid.
In the second block, delegate is implicitly typed as SomeDelegate and although this class conforms to SomePtotocol, it doesn't implement the optional method someMethod, so you get an error.
If you change your second block to
let delegate: SomePtotocol = SomeDelegate()
delegate.someMethod?()
which is equivalent to the first block, then there is no error.

Getter for object property needs to return UnsafeMutablePointer<T>?

I'm working in Swift and one of the protocols I'm using needs to return an UnsafeMutablePointer<T> of a particular object.
I have something like this:
#objc var myProperty:UnsafeMutablePointer<someObject>
{
get
{
// I call a class function here to get a 'someObject'
// return object which I need to pass back a pointer to it.
return UnsafeMutablePointer<someObject>
}
}
The problem is that Xcode doesn't like this. It complains that '>' is not a unary operator.
I've also tried removing the UnsafeMutablePointer<> and use an & in front of someObject but it complains that the & is to be used immediately in a list of arguments for a function.
I suppose I just can't find the right syntax for this? Any help would be appreciated.
If someObject has the type SomeClass, then you need to update your declaration like this:
#objc var myProperty:UnsafeMutablePointer<SomeClass>
{
get
{
return UnsafeMutablePointer<SomeClass>(unsafeAddressOf(someObject))
}
}
The generic argument needs to be the type of the returned data, and you also need to intialize a specialized UnsafeMutablePointer with the memory address of the desired object.

Cannot have a function with same name as parameter type

I have a class that conforms to an Objective-C protocol and has a function with the same name as one of it's parameter types.
class MessageDataController: NSObject, MCOHTMLRendererDelegate {
#objc func MCOAbstractMessage(msg: MCOAbstractMessage!, canPreviewPart part: MCOAbstractPart!) -> Bool {
return false
}
}
This causes Xcode to give the error
"Use of undeclared type 'MCOAbstractMessage'"
for using MCOAbstractMessage as both the function name and a parameter type. It doesn't give an error if I change the function name to abstractMessage or similar. I think the issue is related to this question and/or this issue but am unsure how to resolve. My project's header file is correctly configured to use MailCore2.
Tried changing the declaration to:
#objc(MCOAbstractMessage:canPreviewPart:) func abstractMessage(msg: MCOAbstractMessage!, canPreviewPart part: MCOAbstractPart!) -> Bool
which gives the error
"~/src/project/MessageDataController.swift:11:52: Objective-C method 'MCOAbstractMessage:canPreviewPart:' provided by method 'abstractMessage(:canPreviewPart:)' conflicts with optional requirement method 'MCOAbstractMessage(:canPreviewPart:)' in protocol 'MCOHTMLRendererDelegate'"
This may be solved by using the fully-qualified type name in the parameter list. I'm not familiar with the library you are using, but the suggestion below assumes that the type MCOAbstractMessage is declared in a module called MCO. Prepend MCO. to the type name.
class MessageDataController: NSObject, MCOHTMLRendererDelegate {
#objc func MCOAbstractMessage(msg: MCO.MCOAbstractMessage!, canPreviewPart part: MCOAbstractPart!) -> Bool {
return false
}
}
I tested this by adding a method called Array to one of my classes. Sure enough it threw compiler errors everywhere else that I had used Array as a type. I prefixed all of those as Swift.Array and all was well.
If you want a shorter version, use a typealias,

Can we add #objc for swift function that returns optional value?

I have a swift method like:
public func xIndexAtPoint(point: CGPoint) -> Int?
I want to expose it to Objective-C runtime, so I add #objc before it.
Method cannot be marked #objc because its result type cannot be represented in Objective-C
I am not sure why optional value is not allowed, since Apple does not
mention it in https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html
You’ll have access to anything within a class or protocol that’s marked with the #objc attribute as long as it’s compatible with Objective-C. This excludes Swift-only features such as those listed here:
Generics
Tuples
Enumerations defined in Swift
Structures defined in Swift
Top-level functions defined in Swift
Global variables defined in Swift
Typealiases defined in Swift
Swift-style variadics
Nested types
Curried functions
Int is a structure defined in Swift which listed in Swift-only features
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Reference/Swift_Int_Structure/index.html#//apple_ref/swift/struct/s:Si
So the answer is No
you need to break it into two function or some other workaroud
An Objective-C function can't return a pointer to an Int. You will need to create a wrapper function like:
#objc(xIndexAtPoint:)
public func _xIndexAtPoint(point: CGPoint) -> Int {
return xIndexAtPoint(point: point) ?? NSNotFound
}
Then in Objective-C, you can test for NSNotFound
NSInteger i = [foo xIndexAtPoint:CGPointMake(10, 10)];
if(i == NSNotFound) {
}

Swift vs ObjC initialisation process?

In ObjectiveC we create objects like
-(instancetype)init()
{
return [super init]; // Here it returns initialised value
}
Class *obj = [[Class alloc]init]
But swift initialiser wont return any value.
From Swift docs
Unlike Objective-C initializers, Swift initializers do not return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they are used for the first time.
init()
{
super.init()
}
let obj = Class()
Now how swift initialiser returns the instance to variable obj?.
How the allocation and initialisation occurs in swift?
As #NikolayKasyanov says, with the init family of initialisers, the return (of self) is implicit, and you can't return nil. However, if you want to initialise an optional that could return nil, use a class function. EG:
class NumberLessThan5: Int {
var myNumber: Int
init (i: Int) {
self.myNumber = i
}
class func createWithInt(i: Int) -> NumberLessThan5? {
if i < 5 {
return NumberLessThan5(i)
} else {
return nil
}
}
}
It's just a convention. Swift initialiser sets up a valid instance and could not theoretically return anything other that a valid instance, so there's no point in explicit return.
So (from my point of view) allocation & initialisation sequence looks like this:
Runtime allocates instance of requested class
Initializer is called with self set to allocated instance
Initializer performs setup
Runtime returns initialised instance to client code
Although this approach breaks some useful Objective-C patterns like initialisers returning nil on error, the guarantee that instantiation always succeeds allows compiler to perform some optimisations. Also without dropping initialisers returning nil it would be impossible to actually remove nil from language, it would seem weird if initialisers were returning optionals.
Initialisers DO NOT return any value explicitly because it's not called directly by the code(actually it returns a value which is opaque to user ).
Initialisers are invoked by memory allocation and object initialization code in the runtime, on creating a new instance for a particular type (type- struct or class).Runtime uses variable's type data generated by the compiler to determine how much space is required to store an object instance in memory.
After this space is allocated, the initialiser is called as an internal part of initialisation process to initialise the contents of the fields. Then, when the initialiser exits, the runtime returns the newly-created instance.

Resources