Access self in swift lazy var [duplicate] - closures

I have something that really puzzles me, specifically the following code triggers a compiler error "unresolved identifier self", and I am not sure why this is happening, as lazy means that at the time the property will be used, the class is already instantiated. Am I missing something?
Many thanks in advance.
Here is the code
class FirstClass {
unowned var second: SecondClass
init(second:SecondClass) {
self.second = second
print("First reporting for duty")
}
func aMethod() {
print("First's method reporting for duty")
}
}
class SecondClass {
lazy var first = FirstClass(second: self)
func aMethod() {
first.aMethod()
}
}

For some reason, a lazy property needs an explicit type annotation if its
initial value refers to self. This is mentioned on the swift-evolution mailing list, however I cannot explain why that is
necessary.
With
lazy var first: FirstClass = FirstClass(second: self)
// ^^^^^^^^^^^^
your code compiles and runs as expected.
Here is another example which demonstrates that the problem occurs
also with structs, i.e. it is unrelated to subclassing:
func foo(x: Int) -> Int { return x + 1 }
struct MyClass {
let x = 1
lazy var y = foo(0) // No compiler error
lazy var z1 = foo(self.x) // error: use of unresolved identifier 'self'
lazy var z2: Int = foo(self.x) // No compiler error
}
The initial value of y does not depend on self and does not need a
type annotation. The initial values of z1/z2 depend on self,
and it compiles only with an explicit type annotation.
Update: This has been fixed in Swift 4/Xcode 9 beta 3,
lazy property initializers can now reference instance members without explicit self, and without explicit type annotation. (Thanks to #hamish for the update.)

Related

UIPanGestureRecognizer doesn't work without specified type [duplicate]

I have something that really puzzles me, specifically the following code triggers a compiler error "unresolved identifier self", and I am not sure why this is happening, as lazy means that at the time the property will be used, the class is already instantiated. Am I missing something?
Many thanks in advance.
Here is the code
class FirstClass {
unowned var second: SecondClass
init(second:SecondClass) {
self.second = second
print("First reporting for duty")
}
func aMethod() {
print("First's method reporting for duty")
}
}
class SecondClass {
lazy var first = FirstClass(second: self)
func aMethod() {
first.aMethod()
}
}
For some reason, a lazy property needs an explicit type annotation if its
initial value refers to self. This is mentioned on the swift-evolution mailing list, however I cannot explain why that is
necessary.
With
lazy var first: FirstClass = FirstClass(second: self)
// ^^^^^^^^^^^^
your code compiles and runs as expected.
Here is another example which demonstrates that the problem occurs
also with structs, i.e. it is unrelated to subclassing:
func foo(x: Int) -> Int { return x + 1 }
struct MyClass {
let x = 1
lazy var y = foo(0) // No compiler error
lazy var z1 = foo(self.x) // error: use of unresolved identifier 'self'
lazy var z2: Int = foo(self.x) // No compiler error
}
The initial value of y does not depend on self and does not need a
type annotation. The initial values of z1/z2 depend on self,
and it compiles only with an explicit type annotation.
Update: This has been fixed in Swift 4/Xcode 9 beta 3,
lazy property initializers can now reference instance members without explicit self, and without explicit type annotation. (Thanks to #hamish for the update.)

What if I want to assign a property to itself?

If I attempt to run the following code:
photographer = photographer
I get the error:
Assigning a property to itself.
I want to assign the property to itself to force the photographer didSet block to run.
Here's a real-life example: In the "16. Segues and Text Fields" lecture of the Winter 2013 Stanford iOS course (13:20), the professor recommends writing code similar to the following:
#IBOutlet weak var photographerLabel: UILabel!
var photographer: Photographer? {
didSet {
self.title = photographer.name
if isViewLoaded() { reload() }
}
}
override func viewDidLoad() {
super.viewDidLoad()
reload()
}
func reload() {
photographerLabel.text = photographer.name
}
Note: I made the following changes: (1) the code was switched from Objective-C to Swift; (2) because it's in Swift, I use the didSet block of the property instead of the setPhotographer: method; (3) instead of self.view.window I am using isViewLoaded because the former erroneously forces the view to load upon access of the view property; (4) the reload() method (only) updates a label for simplicity purposes, and because it resembles my code more closely; (5) the photographer IBOutlet label was added to support this simpler code; (6) since I'm using Swift, the isViewLoaded() check no longer exists simply for performance reasons, it is now required to prevent a crash, since the IBOutlet is defined as UILabel! and not UILabel? so attempting to access it before the view is loaded will crash the application; this wasn't mandatory in Objective-C since it uses the null object pattern.
The reason we call reload twice is because we don't know if the property will be set before or after the view is created. For example, the user might first set the property, then present the view controller, or they might present the view controller, and then update the property.
I like how this property is agnostic as to when the view is loaded (it's best not to make any assumptions about view loading time), so I want to use this same pattern (only slightly modified) in my own code:
#IBOutlet weak var photographerLabel: UILabel?
var photographer: Photographer? {
didSet {
photographerLabel?.text = photographer.name
}
}
override func viewDidLoad() {
super.viewDidLoad()
photographer = photographer
}
Here instead of creating a new method to be called from two places, I just want the code in the didSet block. I want viewDidLoad to force the didSet to be called, so I assign the property to itself. Swift doesn't allow me to do that, though. How can I force the didSet to be called?
Prior to Swift 3.1 you could assign the property name to itself with:
name = (name)
but this now gives the same error: "assigning a property to itself".
There are many other ways to work around this including introducing a temporary variable:
let temp = name
name = temp
This is just too fun not to be shared. I'm sure the community can come up with many more ways to do this, the crazier the better
class Test: NSObject {
var name: String? {
didSet {
print("It was set")
}
}
func testit() {
// name = (name) // No longer works with Swift 3.1 (bug SR-4464)
// (name) = name // No longer works with Swift 3.1
// (name) = (name) // No longer works with Swift 3.1
(name = name)
name = [name][0]
name = [name].last!
name = [name].first!
name = [1:name][1]!
name = name ?? nil
name = nil ?? name
name = name ?? name
name = {name}()
name = Optional(name)!
name = ImplicitlyUnwrappedOptional(name)
name = true ? name : name
name = false ? name : name
let temp = name; name = temp
name = name as Any as? String
name = (name,0).0
name = (0,name).1
setValue(name, forKey: "name") // requires class derive from NSObject
name = Unmanaged.passUnretained(self).takeUnretainedValue().name
name = unsafeBitCast(name, to: type(of: name))
name = unsafeDowncast(self, to: type(of: self)).name
perform(#selector(setter:name), with: name) // requires class derive from NSObject
name = (self as Test).name
unsafeBitCast(dlsym(dlopen("/usr/lib/libobjc.A.dylib",RTLD_NOW),"objc_msgSend"),to:(#convention(c)(Any?,Selector!,Any?)->Void).self)(self,#selector(setter:name),name) // requires class derive from NSObject
unsafeBitCast(class_getMethodImplementation(type(of: self), #selector(setter:name)), to:(#convention(c)(Any?,Selector!,Any?)->Void).self)(self,#selector(setter:name),name) // requires class derive from NSObject
unsafeBitCast(method(for: #selector(setter:name)),to:(#convention(c)(Any?,Selector,Any?)->Void).self)(self,#selector(setter:name),name) // requires class derive from NSObject
_ = UnsafeMutablePointer(&name)
_ = UnsafeMutableRawPointer(&name)
_ = UnsafeMutableBufferPointer(start: &name, count: 1)
withUnsafePointer(to: &name) { name = $0.pointee }
//Using NSInvocation, requires class derive from NSObject
let invocation : NSObject = unsafeBitCast(method_getImplementation(class_getClassMethod(NSClassFromString("NSInvocation"), NSSelectorFromString("invocationWithMethodSignature:"))),to:(#convention(c)(AnyClass?,Selector,Any?)->Any).self)(NSClassFromString("NSInvocation"),NSSelectorFromString("invocationWithMethodSignature:"),unsafeBitCast(method(for: NSSelectorFromString("methodSignatureForSelector:"))!,to:(#convention(c)(Any?,Selector,Selector)->Any).self)(self,NSSelectorFromString("methodSignatureForSelector:"),#selector(setter:name))) as! NSObject
unsafeBitCast(class_getMethodImplementation(NSClassFromString("NSInvocation"), NSSelectorFromString("setSelector:")),to:(#convention(c)(Any,Selector,Selector)->Void).self)(invocation,NSSelectorFromString("setSelector:"),#selector(setter:name))
var localVarName = name
withUnsafePointer(to: &localVarName) { unsafeBitCast(class_getMethodImplementation(NSClassFromString("NSInvocation"), NSSelectorFromString("setArgument:atIndex:")),to:(#convention(c)(Any,Selector,OpaquePointer,NSInteger)->Void).self)(invocation,NSSelectorFromString("setArgument:atIndex:"), OpaquePointer($0),2) }
invocation.perform(NSSelectorFromString("invokeWithTarget:"), with: self)
}
}
let test = Test()
test.testit()
There are some good workarounds but there is little point in doing that.
If a programmer (future maintainer of the code) sees code like this:
a = a
They will remove it.
Such a statement (or a workaround) should never appear in your code.
If your property looks like this:
var a: Int {
didSet {
// code
}
}
then it's a not a good idea to invoke the didSet handler by assignment a = a.
What if a future maintainer adds a performance improvement to the didSet like this?
var a: Int {
didSet {
guard a != oldValue else {
return
}
// code
}
}
The real solution is to refactor:
var a: Int {
didSet {
self.updateA()
}
}
fileprivate func updateA() {
// the original code
}
And instead of a = a directly call updateA().
If we are speaking about outlets, a suitable solution is to force the loading of views before assigning for the first time:
#IBOutlet weak var photographerLabel: UILabel?
var photographer: Photographer? {
didSet {
_ = self.view // or self.loadViewIfNeeded() on iOS >= 9
photographerLabel?.text = photographer.name // we can use ! here, it makes no difference
}
}
That will make the code in viewDidLoad unnecessary.
Now you might be asking "why should I load the view if I don't need it yet? I want only to store my variables here for future use". If that's what you are asking, it means you are using a view controller as your model class, just to store data. That's an architecture problem by itself. If you don't want to use a controller, don't even instantiate it. Use a model class to store your data.
I hope one day #Swift developers will fix this miscuzzi :)
Simple crutch:
func itself<T>(_ value: T) -> T {
return value
}
Use:
// refresh
style = itself(style)
image = itself(image)
text = itself(text)
(optionals including)
Make a function that the didSet calls then call that function when you want to update something? Seems like this would guard against developers going WTF? in future
#vacawama did a great job with all those options. However in iOS 10.3, Apple banned some of these ways and most likely will be doing it in the future again.
Note: To avoid the risk and future errors, I will use a temporary variable.
We can create a simple function for that:
func callSet<T>(_ object: inout T) {
let temporaryObject = object
object = temporaryObject
}
Would be used like: callSet(&foo)
Or even a unary operator, if there is a fitting one ...
prefix operator +=
prefix func +=<T>(_ object: inout T) {
let temporaryObject = object
object = temporaryObject
}
Would be used like: +=foo

access property from another class

I have a custom swift class like this
class NichedHelper: NSObject {
private var _theController:UIViewController? = nil
var theController:UIViewController? {
get {
return self._theController
}
set {
self._theController = newValue
}
}...
it has an implementation function like this and _theController passing a Lobb class that inherit UIViewController
func DoPump(from: String, theBoard: CGRect, overide: Bool) {
let abil:AnyObject = _theController!
abil.bottomConst.constant = -80
}
it throw error 'AnyObject' does not have a member named 'bottomConst'.
since i don't know what the english word for this kind of technique, so that will be my first question.
my second question, is it possible if i am sure Lobb class (or other class) have a variable called bottomConst, how can i access it from class NichedHelper?
you have declared the _theController as private , remove that just declare as
var _theController:UIViewController!
// this is how we roll in swift ;) bye bye Objective-C
I don't know exactly what you are trying to do and why you have two UIViewController instances. So I'm not able to answer your first question but regarding your second one, you have to cast the object to a UIViewController object:
func DoPump(from: String, theBoard: CGRect, overide: Bool) {
let abil:AnyObject = _theController as! UIViewController
abil.bottomConst.constant = -80
}
This at least should make the compiling error away, if you have the bottomConst attribute declared as a variable of UIViewControllers in an extension (since they do not have this variable normally.
Well, i change from passing the UIViewController to NSLayoutConstraint

Swift error: "class cannot be constructed because it has no accessible initializers"

Xcode is giving me this error for my Swift code:
'myColor' cannot be constructed because it has no accessible initializers
import Foundation
protocol Prototype {
func Clone<T>() -> T
}
class myColor: Prototype {
var red: Int?
var green: Int?
var blue: Int?
init () {}
func Clone<myColor>() -> myColor {
let newColor = myColor()
newColor.red = self.red
newColor.green = self.green
newColor.blue = self.blue
return newColor
}
}
The error is on line:
let newColor = myColor()
Type 'myColor' has no member 'init'
Even if you set your framework to public, you still need to declare all classes you want to make accessible as 'public'. Same goes for your init method.
public init() {
}
Did the trick for me.
First, classes have leading caps. Methods have leading lowercase. You mean MyColor and clone().
You're confusing the compiler at this point:
func Clone<myColor>() -> myColor {
It thinks you mean that myColor is a type variable that is shadowing the class name. So when you get to myColor(), it's basically the same thing as T(), which has no trivial constructor.
If you fix this stuff up, you'll find that the correct error is
Type 'MyColor' does not conform to protocol 'Prototype'
That error is a completely different problem. See Protocol func returning Self for an explanation of how to implement a copy protocol. You also may be interested in the followup: Swift protocol and return types on global functions.
You will hit this error if you attempt to add a new property to a subclass without adding new initializers.
'SomeSubclass' cannot be constructed because it has no accessible initializers
Suddenly none of the existing superclass's initializers will be valid, as the new variable needs to be set within an init() method on the subclass (which doesn't yet exist).
class SomeSubclass: UIViewController { // Class 'SomeSubclass' has no initializers
var date: Date
class func `for`(_ date: Date) -> SomeSubclass {
let someSubclass = SomeSubclass() // 'SomeSubclass' cannot be constructed because it has no accessible initializers
someSubclass.date = date
return someSubclass
}
}
A fix for most UIViewController situations, as is commonly used for IBOutlets, is to declare the subclass's properties as optionals or implicitly unwrapped optionals, which will be valid and initialized to nil when using the existing superclass init methods. Then set the value immediately after initialization.
var date: Date?
// - or - //
var date: Date!
Seems generic generates extend of class, and need for use.
override init() {...
Note that any class in Swift must have initializer.
And in your case nevertheless generic, class must have init()

Swift function that return two strings fail when its in loop

I Wrote a function that return two Strings, when calling the function regularly its works fine, but when I'm running the function through loop, I'm getting this error:
Thread 1: EXC_BAD_ACCESS (code=2, address=0xbfffcba0)
override func viewDidLoad()
{
super.viewDidLoad()
test()
}
func test()
{
var funcs = [checkButton]
var a = checkButton(value: 1) // Runs OK
for f in funcs{
var result = f(value: 1) // Fail
}
}
func checkButton(#value: Int) -> (location: String, pattern: String){
return ("abc","cba")
}
Update:
I'm using Xcode 6 beta 2, and running Mavericks on VMware Workstation.
Also, I've just created new clean project with that code and still getting the error.
This code runs fine for me. Your EXC_BAD_ACCESS must be coming from some other part of your code. Try setting a breakpoint and stepping through the code to find the line throwing the error.
From the “The Swift Programming Language.”
“An instance method can be called only on a specific instance of the type it belongs to. It cannot be called in isolation without an existing instance.”
checkButton() is an instance method, not a closure. It works in the first case because there is an implicit self. before checkButton(). It will not work in the second case.
If you want to make checkButton a closure you could declare it like so:
let checkButton = { (#value: Int) -> (location: String, pattern: String) in
return ("abc","cba")
}
I can confirm that it doesn't work for me either. Created a iOS single-view app from template, and added above code. crash. As an experiment, I took it out of the array (just f = self.checkButton) and got the same result.
I think it's a bug in the compiler.
First according to the book, a method is actually a function which is actually a closure, albeit one with special properties and restrictions. Shouldn't self.checkButton (or implicit version) be sufficient to "give it an existing instance", making it a closure? If MattL is correct that instance methods can't be used as closures, then the compiler shouldn't allow you to assign one to anything.
Second, the crash occurs on the exit, not on the call. And if you reference self in checkButton, (e.g. println(self.title) having previously set title), it works fine. That suggests that the instance is indeed known and operating, just something wrong on the return.
Third, changing it to a class method doesn't help. Changing these lines
var a = ViewController.checkButton(value: 1)
var funcs = [ViewController.checkButton]
class func checkButton(#value: Int) -> (location: String, pattern: String)
results in the same crash. I don't see any similar prohibition on context for class methods.
Fourth, if you simply change the return type from (location: String, pattern: String) to just String and return abc, then the whole thing works fine.
Fourth, if you wrap test and checkButton in a new class testClass, and then call it as below, it works:
class testClass {
func test()
{
var funcs = [checkButton]
var a = checkButton(value: 1) // Runs OK
for f in funcs {
var result = f(value: 1) // Fail
println(result)
}
}
func checkButton(#value: Int) -> (location: String, pattern: String){
return ("abc","cba")
}
}
class ViewController: UIViewController {
override func viewDidLoad()
{
super.viewDidLoad()
let g = testClass()
g.test()
}
}
Now change testClass to testClass: NSObject and it crashes.
So it looks like the compiler is botching up a method return when called as a closure with a tuple in a Obj-C subclass. When I put it like that, I must say that it's not terribly surprising nobody's noticed yet; you're really pushing the edge here!
More practically, in the meantime, if it's helpful, an alternative to changing your method to a closure is to keep it unchanged and just wrap it as you put it in the array:
var funcs = [{value in self.checkButton(value: value)}]
This seems to work.

Resources