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.
Related
I created this Swift class:
#objc public class Tester: NSObject {
private var name: String
private var user: Users
init(string:String, user: Users) {
print(user.empId)
print(user.name)
self.user = user
self.name = string
super.init()
}
}
I call the initializer from Obj C like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
NSString * nilString = nil;
Users * nilUser = nil;
Tester * test = [[Tester alloc] initWithString:nilString user:nilUser];
return YES;
}
Here I pass nil for the parameters to the Swift initializer. Ideally I expect this to crash as the initializer only accepts non-nil values.
But what actually happens is, when the execution point reaches inside the initializer, new parameter objects are created:
The nil string becomes "" and the User variable that was nil is now pointing to an object.
But for a property like this
#property(nonatomic,strong) SomeClass * object;
where
object = nil;
When I call this object from swift,
let x = object.someGetter;
This crashes.
At one point, If I pass nil to some non null, it works and at another point, it crashes. Why does this weird behavior exist? If for some reasons, my parameters are nil, and passed to nonnull, I would like this to crash. So that I can fix things.
EDIT: This became so unexpected, further trying to play with this code.
The string parameter was actually as string, but the User shows uninitialized, hence manipulations on string worked well, but the user object, took the changes but did not showed them back.
So there are three questions:
first, why does accessing the user properties not crash,
second, why is there an empty string instead of a nil one,
third, why does assigning a property (of a custom class) crash
I'll answer all of them :-)
1. Accessing the Users properties
Swift uses Objective C messaging when accessing the properties of the Users class, (I assume - Users is an ObjC-Class as seen in the debugger output; base class NSObject).
In the disassembly view, one can see this:
0x1000018be <+78>: movq 0x3e6e2b(%rip), %rsi ; "empId"
....
0x1000018d7 <+103>: callq 0x100361b10 ; symbol stub for: objc_msgSend
Since objc_msgSend supports nil messaging, the call does not fail.
2. Empty String magic
When calling the Swift initializer from Objective C, the bridging code creates the following:
0x100001f45 <+53>: callq 0x100021f50
; static (extension in Foundation):
;Swift.String._unconditionallyBridgeFromObjectiveC (Swift.Optional<__ObjC.NSString>) -> Swift.String
....
0x100001f5b <+75>: callq 0x100001870
; TestCalling.Tester.init (string : Swift.String, user : __ObjC.ObjCUser) -> TestCalling.Tester at SwiftClass.swift:14
The interesting part here is the _unconditionallyBridgeFromObjectiveC call. This will internally call the Swift.String function _cocoaStringToSwiftString_NonASCII, and checking the source code (here, line 48), you can see the following:
#inline(never) #_semantics("stdlib_binary_only") // Hide the CF dependency
func _cocoaStringToSwiftString_NonASCII(
_ source: _CocoaString
) -> String {
let cfImmutableValue = _stdlib_binary_CFStringCreateCopy(source)
let length = _stdlib_binary_CFStringGetLength(cfImmutableValue)
let start = _stdlib_binary_CFStringGetCharactersPtr(cfImmutableValue)
return String(_StringCore(
baseAddress: start,
count: length,
elementShift: 1,
hasCocoaBuffer: true,
owner: unsafeBitCast(cfImmutableValue, to: Optional<AnyObject>.self)))
}
The function always returns a new Swift.String object, in our case an empty one! So, again no crash.
3. Property access
When accessing a custom property, e.g. assigning it to a variable:
let x:SomeClass = object.someGetter;
the following happens:
The return value of someGetter will be retained (objc_retainAutoreleasedReturnValue) -- this does not crash
The returned object will be implicitly unwrapped -- which then crashes
If x were a weak property, or an optional, the code wouldn't crash. Even when using type inference, it does not crash (on my machine, swift 4):
let x = object.someGetter;
This is, because the inferred type of x is an optional SomeClass? unless the property itself is declared as nonnull:
#property(nonatomic,strong, nonnull) SomeClass * object;
When you say the string is "" and the user is an object, it looks like you're just relying on the debugger's variable view for this, correct? Because the console output clearly shows nil twice.
What's happening here is the generated code for the initializer doesn't actually do anything that would crash if the values are nil. Semantically speaking, yes, it's invalid, but the actual machine code isn't doing something that relies on the non-nil assumption. The calls to print() work because, I assume, the code that converts the arguments into Any existentials happens to work even though the values are unexpectedly nil, and produce a nil Any.
As for the debugger view, it's a debugger, it's just doing the best it can to interpret the variables, but it's not actually running the Swift standard library. I'm not entirely sure why the string variable is showing up as "", I guess because it's always showing a string representation and it determines that it has no data (and a string with no data is ""). As for user, it actually shows it as 0x0000000000000000 which is correct, that means it's the null pointer (i.e. nil).
And then finally, let x = object.someGetter does crash, because the resulting code depends on the value being non-nil (specifically, it's presumably calling swift_retain() or swift_unknownRetain() on the value, which requires the argument to be non-nil as it dereferences the pointer).
In a simple example like this, I can omit self for referencing backgroundLayer because it's unambiguous which backgroundLayer the backgroundColor is set on.
class SpecialView: UIView {
let backgroundLayer = CAShapeLayer()
init() {
backgroundLayer.backgroundColor = UIColor.greenColor().CGColor
}
}
But, just like in Objective-C, we can confuse things by adding local variables (or constants) named similarly. Now the backgroundColor is being set on the non-shape layer:
class SpecialView: UIView {
let backgroundLayer = CAShapeLayer()
init() {
var backgroundLayer = CALayer()
backgroundLayer.backgroundColor = UIColor.greenColor().CGColor
}
}
(this is resolved by using self.backgroundLayer.backgroundColor)
In Objective-C I always eschewed ivars for properties and properties were always prefixed with self for clarity. I don't have to worry about ivars in swift but are there other considerations for when I should use self in swift?
The only times self is required are when referencing a property inside a closure and, as you pointed out, to differentiate it from a local variable with the same name.
However, personally, I prefer to always write "self" because:
That is an instant and obvious sign that the variable is a property. This is important because it being a property means that its state can vary more widely and in different ways than a local variable. Also, changing a property has larger implications than changing a local variable.
The code does not need to be updated if you decide to introduce a parameter or variable with the same name as the property
Code can be easily copied in and out of closures that do require self
Most of the time we can skip self. when we access class properties.
However there is one time when we MUST use it: when we try to set self.property in a closure:
dispatch_async(dispatch_get_main_queue(), {
// we cannot assign to properties of self
self.view = nil
// but can access properties
someFunc(view)
})
one time when we SHOULD use it: so you don't mess a local variable with class property:
class MyClass {
var someVar: String = "class prop"
func setProperty(someVar:String = "method attribute") -> () {
print(self.someVar) // Output: class property
print(someVar) // Output: method attribute
}
}
other places where we CAN use self.
before property just to be expressive about were variable/constant comes from.
Looking at Ray Wenderlich's style guide
Use of Self
For conciseness, avoid using self since Swift does not require it to access an object's properties or invoke its methods.
Use self only when required by the compiler (in #escaping closures, or in initializers to disambiguate properties from arguments). In other words, if it compiles without self then omit it.
Swift documentation makes the same recommendation.
The self Property
Every instance of a type has an implicit property called self, which is exactly equivalent to the instance itself. You use the self property to refer to the current instance within its own instance methods.
The increment() method in the example above could have been written like this:
func increment() {
self.count += 1
}
In practice, you don’t need to write self in your code very often. If you don’t explicitly write self, Swift assumes that you are referring to a property or method of the current instance whenever you use a known property or method name within a method. This assumption is demonstrated by the use of count (rather than self.count) inside the three instance methods for Counter.
The main exception to this rule occurs when a parameter name for an instance method has the same name as a property of that instance. In this situation, the parameter name takes precedence, and it becomes necessary to refer to the property in a more qualified way. You use the self property to distinguish between the parameter name and the property name.
Here, self disambiguates between a method parameter called x and an instance property that is also called x:
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.x > x
}
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
print("This point is to the right of the line where x == 1.0")
}
// Prints "This point is to the right of the line where x == 1.0"
I'm going to go against the flow and not use self unless absolutely required.
The reason why is that two of the main reasons to use self is
When capturing self in a block
When setting self as a delegate
In both cases, self will be captured as a strong reference. This might be what you want, but in many cases, you actually want to use a weak one.
Therefor, forcing the developer to use self as an exception and not a rule will make this strong capture more conscious, and let him reflect on this decision.
As Apple documentation says in https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html
The self Property
Every instance of a type has an implicit property called self, which
is exactly equivalent to the instance itself. You use the self
property to refer to the current instance within its own instance
methods.
The increment() method in the example above could have been written
like this:
func increment() {
self.count += 1
}
In practice, you don’t need to write self in your code very often. If
you don’t explicitly write self, Swift assumes that you are referring
to a property or method of the current instance whenever you use a
known property or method name within a method. This assumption is
demonstrated by the use of count (rather than self.count) inside the
three instance methods for Counter.
The main exception to this rule occurs when a parameter name for an
instance method has the same name as a property of that instance. In
this situation, the parameter name takes precedence, and it becomes
necessary to refer to the property in a more qualified way. You use
the self property to distinguish between the parameter name and the
property name.
Here, self disambiguates between a method parameter called x and an
instance property that is also called x:
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.x > x
}
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
print("This point is to the right of the line where x == 1.0")
}
// Prints "This point is to the right of the line where x == 1.0"
Without the self prefix, Swift would assume that both uses of x
referred to the method parameter called x.
I would prefer to keep using self whenever I'm using a property to omit these misunderstandings.
As Nick said, in objective-c we had ivars + synthesized properties which gave the _internal variable names to delineate things. Eg.
#IBOutlet (nonatomic,strong) UITableView *myTableView;
resulting in _myTableView to be (preferably) referenced internally - and self.myTableView to be reference beyond the class. While this is pretty black and white, consider the exception when programmatically instantiating views, you can gain clarity/ simplicity / reduce boilerplate by removing self.
#interface CustomVC:UIViewController
{
UITableView *myTableView;
}
In swift, the public / internal properties clarify this scope.
If it's a public property that other classes will interact with err on self.
Otherwise if it's internal skip self and avoid the automatic repetition.
The compiler will catch you when it's needed.
// UIViewcontroller swift header
public var title: String? // Localized title for use by a parent controller.
public var navigationItem: UINavigationItem { get }
/// In your class
self.title = "Clarity"
self.navigationItem.leftBarButtonItem = UIBarButtonItem()
// In superclass
#property(nonatomic, copy) NSString *screenName // use self.screenName in swift subclass
#IBOutlet myTableView:UITableView // use self
public var myTableView:UITableView // use self
internal var myTableView:UITableView // skip self
var myTableView:UITableView // skip self
From a few initial tutorials, I see that properties belong to a Class and are essentially 'global variables' as used in the C++ world (coded in this years ago). I also see variables as more of a 'local' entities only used / storing information within a method.
Then I came across this Quora thread: https://www.quora.com/Apple-Swift-programming-language/What-is-the-difference-between-a-property-and-a-variable
Now I see properties being able to execute code associated with their invocation. This is very cool, but also opened up a whole bunch of other questions for me.
Are there other simple and clear ways to remember the distinction between a property and a variable?
Properties belong to an object, whereas variables do not. A variable can be declared without having to be associated with a particular class, or other object. A property must be associated with a particular object (i.e.: a class, enum, or struct)
Local variables are just things that you work with. You have full control over these, and if you change a variable in a function, nothing outside of your function is ever gonna know. If I write a framework and you use it, and I decide to change something about a function's local variables, your app that uses my framework will keep working just as if nothing changed.
Classes, on the other hand, describe a contract. When you use a class, you have access to everything they publicly advertise. This means that if I write a framework and you use it, if I ever change or remove a public member on a class, your code will break if you were previously using that member.
For this reason, in many languages, it's bad practice to mark instance variables as public. Instance variables having no logic attached, if I want at some point to trigger something when a field is changed or if I want to remove the field entirely (and instead report a value in a sub-object or something), then I'm stuck with changing the public contract (turning the field in a pair of get/set methods, for instance), and possibly breaking your code.
Swift makes properties an indirection for this reason. Swift properties can be treated as dumb values for the most part, but if you ever need to change from a stored value to a computed value or something, you can do it without changing your class's interface. That way, you don't break existing code that relies on the property.
Swift variable, constant, Property
[Swift types]
variable - named storage of address. Every variable has a type which defines a memory size, attributes and behaviours
Swift variable and constants
constant is a variable but can not be modified after definition.
//definition
var <name> = <initial_value>
//type annotation
var <name>: <Swift_type> [= <initial_value>] // [] is optional
//var - variable
var myVariable1 = 11
var myVariable2: Int
myVariable2 = 12
//let - constant
let myConstant1 = 21
let myConstant2: Int
myConstant2 = 22
Global and local variable
Global variable is a variable which is defined out of function, class.
Local variable is: variable inside a type context(class, struct, enum)[About], inside a function, function parameter
Property
property - associate value with a type context. It is a variable + bounded getter/setter. It has field syntax but uses methods(getter/setter) under the hood.
Stored properties and computed properties
They can belong to instance(instance property) or type(type property):
Stored property (class, structure)
Computed property (class, structure, enum)
Stored property - is a local variable -> variable inside a type context. Swift stored property does not support instance variable like Objective-C.
variable stored properties - var
constant stored properties - let
It supports property observers (willSet, didSet)
Computed property - provide getter and optional setter to calculate a value every time
public class Person {
var firstName = "John"
var lastName = "Wick"
var fullNameComputedProperty: String {
get {
return "\(firstName) \(lastName)"
}
//optional
set {
let arr = newValue.split(separator: " ")
firstName = String(arr[0])
lastName = String(arr[1])
}
}
var addressStoredProperty: String {
//Property Observers
willSet {
print("old address:\(addressStoredProperty)")
print("new address:\(newValue)")
//addressStoredProperty is not updated yet
}
didSet {
print("old address:\(oldValue)")
print("new address:\(addressStoredProperty)")
}
}
}
Lazy Stored property
Property is calculate during first access to it(on demand)
only var lazy because let must have a value during initialization
Init/customize stored property by closure
Official doc
You are able to init/setup/customise a stored property with a help of closure
() at the end executes the closure immediately and assign a value to stored property(calculate and return a value).
in initializing case it is not possible to access to any instance variable or function because it has not initialized yet
in initializing case it will be executed only once for every object or if you use static - once for the class[Example]
Examples
func testStoredPropertyWithClosure() {
class ClassA { }
class ClassB {
static let staticStoredProperty: ClassA = {
//is called only when you access to it like ClassB.staticStoredProperty
print("init staticStoredProperty")
return ClassA()
}()
var storedProperty: ClassA = {
print("init storedProperty")
//self.foo() //Error: Class declaration cannot close over value 'self' defined in outer scope
return ClassA()
}()
func foo () {
storedProperty = {
print("customize storedProperty")
return ClassA()
}()
}
}
let b = ClassB()
b.foo()
ClassB.staticStoredProperty
}
closure stored property vs Computed property
closure stored property is called once and can be changed after initialization(if it is var)
Computed property is calculated every time when it is called
[Java variable, property...]
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.
I'm having trouble grasping the proper way of instantiating variables that always need to be set before an object is fully functional but may need to be instantiated after the constructor. Based on Swift's other conventions and restrictions it seems like there is a design pattern I'm unaware of.
Here is my use case:
I have a class that inherits from UIViewController and will programmatically create views based on user actions
I need to attach these views to this class, but to do so I need to retrieve their content based on configuration data supplied by another controller
I don't care if this configuration data is passed to the constructor (in which case it would always be required) or supplied by a secondary call to this object before it is used
My problem seems to be that both of the approaches in bullet 3 seem flawed.
In the first case, there is only one legitimate constructor this class can be called with, yet I'm forced to override other constructors and initialize member variables with fake values even if the other constructors are never intended to be used (I'm also trying to keep these variables as let types based on Swift's best practices).
In the second case, I'm effectively splitting my constructor into two parts and introduce an additional point of failure in case the second part fails to be called prior to class being used. I also can't move this second part to a method that's guaranteed to be called prior to usage (such as viewDidLoad) because I still need to pass in additional arguments from the config. While I can make sure to call the initPartTwo manually, I'd prefer to have a mechanism that better groups it with the actual constructor. I can't be the first one to run into this and it seems like there is a pattern I'm not seeing to make this cleaner.
UPDATE:
I ended up going with a modified version of the pattern matt suggested:
struct Thing {
let item1: String
let item2: String
struct Config {
let item3: String
let item4: String
}
var config:Config! {
willSet {
if self.config != nil {
fatalError("tried to initialize config twice")
}
}
}
init() {
self.item1 = ...
self.item2 = ...
...
}
public func phaseTwoInit(item3: String, item4: String) {
self.item3 = item3
self.item4 = item4
...
}
}
var t = Thing()
...
t.phaseTwoInit(...)
...
// start using t
If an initial instance variable property value can't be supplied at object initialization time, the usual thing is to declare it as an Optional. That way it doesn't need to be initialized by the class's initializers (it has a value - it is nil automatically), plus your code subsequently can distinguished uninitialized (nil) from initialized (not nil).
If the Optional if an implicitly unwrapped Optional, this arrangement need have no particular effect on your code (i.e. it won't have to be peppered with unwrappings).
If your objection is that you are forced to open the door to multiple settings of this instance variable because now it must be declared with var, then close the door with a setter observer:
struct Thing {
var name:String! {
willSet {
if self.name != nil {
fatalError("tried to set name twice")
}
}
}
}
var t = Thing()
t.name = "Matt" // no problem
t.name = "Rumplestiltskin" // crash