Swift initializer doesn't return value? - ios

Swift documentation clearly says.
Unlike Objective-C initializers, Swift initializers do not return a
value.
please explain below syntax.
let instanceOfString = String()
It does initialize a String object by calling the initializer and return it. Value get assigned to instanceOfString. Isn't it?

The swift documentation refers to the syntax of a type's init methods.
The syntax omits a return type in the signature and the method usually does not contain a return statement:
init() {
}
Obviously the call of an initializer (String()) does return a value. The difference to Objective-C is that the init method in pure Swift types is not free to return a different object than the target of the method—it's always the implicitly allocated instance of the target type.
The only exception is that it's possible to return nil in failable initializers.

Related

Swift 3 - How to verify class type of object

This line of code used to work with Swift 2, but now is incorrect in Swift 3.
if gestureRecognizer.isMember(of: UITapGestureRecognizer) { }
I get this error: Expected member name or constructor call after type name.
What is the correct way to use isMember(of:)?
Most likely, you'll want to not only check the type, but also cast to that type. In this case, use:
if let gestureRecognizer as? UITapGestureRecognizer { }
else { /* not a UITapGestureRecognizer */ }
Swift casting operators
These operators are only available in Swift, but still work when dealing with Objective C types.
The as operator
The as operator performs a cast when it is known at compile time that the cast always succeeds, such as upcasting or bridging. Upcasting lets you use an expression as an instance of its type’s supertype, without using an intermediate variable.
This is the most preferable operator to use, when possible. It guarentees success, without worrying about unwrapping an optional or risking a crash.
The as? operator
The as? operator performs a conditional cast of the expression to the specified type. The as? operator returns an optional of the specified type. At runtime, if the cast succeeds, the value of expression is wrapped in an optional and returned; otherwise, the value returned is nil. If casting to the specified type is guaranteed to fail or is guaranteed to succeed, a compile-time error is raised.
This is the second most preferable operator to use. Use it to safely handle the case in which a casting operator can't be performed.
The as! operator
The as! operator performs a forced cast of the expression to the specified type. The as! operator returns a value of the specified type, not an optional type. If the cast fails, a runtime error is raised. The behavior of x as! T is the same as the behavior of (x as? T)!.
This is the least preferable operator to use. I strongly advise against abusing it. Attempting to cast an expression to an incompatible type crashes your program.
Swift type checking
If you merely want to check the type of an expression, without casting to that type, then you can use these approaches. They are only available in Swift, but still work when dealing with Objective C types.
The is operator
The is operator checks at runtime whether the expression can be cast to the specified type. It returns true if the expression can be cast to the specified type; otherwise, it returns false
Works on any Swift type, including Objective C types.
Swift equivalent of isKind(of:)
Using type(of:)
Unlike the is operator, this can be used to check the exact type, without consideration for subclasses.
Can be used like: type(of: instance) == DesiredType.self
Swift equivalent of isMember(of:)
Legacy (Objective C) methods for checking types
These are all methods on NSObjectProtocol. They can be used in Swift code, but they only apply work with classes that derive from NSObjectProtocol (such as subclasses of NSObject). I advise against using these, but I mention them here for completeness
isKind(of:)
Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class
Avoid this in Swift, use is operator instead.
isMember(of:)
Returns a Boolean value that indicates whether the receiver is an instance of a given class
Avoid this in Swift, use type(of: instance) == DesiredType.self instead.
conforms(to:)
Returns a Boolean value that indicates whether the receiver conforms to a given protocol.
Avoid this in Swift, use is operator instead.
There are several ways to check the class of an object. Most of the time you will want to use either the is or the as? operators like so:
let gestureRecognizer: UIGestureRecognizer = UITapGestureRecognizer()
// Using the is operator
if gestureRecognizer is UITapGestureRecognizer {
// You know that the object is an instance of UITapGestureRecognizer,
// but the compiler will not let you use UITapGestureRecognizer specific
// methods or properties on gestureRecognizer because the type of the
// variable is still UIGestureRecognizer
print("Here")
}
// Using the as? operator and optional binding
if let tapGestureRecognizer = gestureRecognizer as? UITapGestureRecognizer {
// tapGestureRecognizer is the same object as gestureRecognizer and is
// of type UITapGestureRecognizer, you can use UITapGestureRecognizer
// specific methods or properties.
print("Here")
}
// Using the type(of:) global function
if type(of: gestureRecognizer) == UITapGestureRecognizer.self {
// gestureRecognizer is an instance of UITapGestureRecognizer, but not any
// of its subclasses (if gestureRecognizer was an instance of a subclass of
// UITapGestureRecognizer, the body of this if would not execute).
// This kind of check is rarely usefull, be sure this is really what you
// want to do before you use it.
print("Here")
}
// Using the isKind(of:) method
if gestureRecognizer.isKind(of: UITapGestureRecognizer.self) {
// Like for the is operator, you know that the object is an instance of
// UITapGestureRecognizer (or any subclass of UITapGestureRecognizer).
// This is the Objective-C version of the is operator and will only work
// on classes that inherit from NSObject, don't use it in Swift.
print("Here")
}
// Using the isMember(of:) method
if gestureRecognizer.isMember(of: UITapGestureRecognizer.self) {
// gestureRecognizer is an instance of UITapGestureRecognizer, but not
// any of its subclasses.
// This is the Objective-C version of type(of:) and will only work on
// classes that inherit from NSObject, don't use it in Swift.
print("Here")
}
You have to use .self to refer the class type now.
let a = UITapGestureRecognizer()
print (a.isMember(of: UIGestureRecognizer.self))
There is also:
print (a is UITapGestureRecognizer)
Swift 3:
if gestureRecognizer is UITapGestureRecognizer {
//It's a tap
}

How to pass in a nil type into a paramter in Swift?

I am converting an iOS app from objective-c to swift. In the objective-c version of the app there was a method, AlertViewShow that gets called, and for one of its parameters nil was passed in like below.
AlertViewShow(APPNAME, INTERNET_NOT, nil);
The nil is passed in for a UIAlertViewDelegate type. Now when converting it to Swift I cannot do
AlertViewShow(APPNAME, INTERNET_NOT, nil) //error: cannot pass in nil into paramter
So, by looking at stack forums I tried this...
let alertViewNilObject: UIAlertViewDelegate? = nil
AlertViewShow(APPNAME, INTERNET_NOT, alertViewNilObject!) //compiler doesnt complain
So no errors pop up. But when I run the app it says: "fatal error: unwrapped a nil value".
How do I pass in nil into the parameter in Swift 2.0? Or is there another alternative besides passing in nil?
You need to make the argument itself take an optional value, rather than trying to force unwrap a nil optional (which will always crash).
func AlertViewShow(title:String, desc:String, delegate:AlertViewDelegate?) {
if delegate != nil {
// do some delegate-y things
}
...
}
...
AlertViewShow(title: APPNAME, desc: INTERNET_NOT, delegate: nil)
If it's an obj-c method that you're not re-writing in Swift, you'll just have to add the nullable prefix to the argument.
-(void) AlertViewShow:(NSString*)title desc:(NSString*)description delegate:(nullable UIAlertViewDelegate*)delegate;
(although it's worth noting that method names should start with a lowercase, not an uppercase)
That should then get converted to an optional argument when bridging.

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.

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.

Swift func that takes a Metatype?

As Apple says in the Metatype Type section in Swift's docs:
A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types.
Is there a base class to refer to any class, struct, enum, or protocol (eg MetaType)?
My understanding is that protocol types are limited to use as a generic constraint, because of Self or associated type requirements (well, this is what an Xcode error was telling me).
So, with that in mind, maybe there is a Class base class for identifying class references? Or a Type base class for all constructable types (class, struct, enum)? Other possibilities could be Protocol, Struct, Enum, and Closure.
See this example if you don't get what I mean yet.
func funcWithType (type: Type) {
// I could store this Type reference in an ivar,
// as an associated type on a per-instance level.
// (if this func was in a class, of course)
self.instanceType = type
}
funcWithType(String.self)
funcWithType(CGRect.self)
While generics work great with 1-2 constant associated types, I wouldn't mind being able to treat associated types as instance variables.
Thanks for any advice!
This works:
func funcWithType (type: Any.Type) {
}
funcWithType(String.self)
funcWithType(CGRect.self)
Given your example an implementation would be:
// protocol that requires an initializer so you can later call init from the type
protocol Initializeable {
init()
}
func funcWithType (type: Initializeable.Type) {
// make a new instance of the type
let instanceType = type()
// in Swift 2 you have to explicitly call the initializer:
let instanceType = type.init()
// in addition you can call any static method or variable of the type (in this case nothing because Initializeable doesn't declare any)
}
// make String and CGRect conform to the protocol
extension String: Initializeable {}
extension CGRect: Initializeable {}
funcWithType(String.self)
funcWithType(CGRect.self)

Resources