In my app I read calendar events of type EKEvent, and I've made an extension with a lot of computed vars so I can easily get the duration, number of man-hours etc. for each event in the calendar. But in large scale, the performance is bad - so I want to use lazy vars instead, to cache all my extra data.
Therefore, I want to make a subclass of EKEvent - called CustomEvent, which adds the lazy vars, but my problem is that the EKEventStore always returns EKEvents, and I need to convert that to instances of my CustomEvent subclass, in order to be able to access the lazy vars etc.
A simple typecast is not enough, and I've tried in a playground, to see what could work, but got nothing useful. I need a special constructor for CustomRectangle, which can initialize a CustomRectangle from a NativeRectangle. An alternative solution is to make a wrapper class that holds the original object as a property, but that wouldn't be my favorite solution, since I'd then have to map all methods and properties
class NativeRectangle: NSObject {
var width: Int
var height: Int
init(width: Int, height: Int) {
self.width = width
self.height = height
super.init()
}
}
class CustomRectangle: NativeRectangle {
var area: Int { return width * height}
}
let rect = NativeRectangle(width: 100, height: 20)
let customRect = CustomRectangle(rect) // This fails, i need a constructor
print(customRect.area)
There is no way in Swift (and in general in most Object Oriented languages) to use an existing instance of a base class object when creating a child class instance.
From a general programming stand-point you have the two options in this situation:
Use composition: Make the CustomRectangle contain a NativeRectangle and forward all methods to it that you need.
Use a map to link NativeRectangles to additional information. In Objective C and Swift you can you objc_AssociationPolicy to have such an internal map most easily. See https://stackoverflow.com/a/43056053/278842
Btw. There is no way that you will see any speed-up from "caching" a simple computation as width * height.
If you already work in the Objective-C land, there’s an option to wrap the native class and forward all (except the added) messages automatically:
- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
NSMethodSignature *ours = [super methodSignatureForSelector:selector];
return ours ?: [wrappedObject methodSignatureForSelector:selector];
}
I can’t remember if this is everything that was needed for the forwarding to work, but it should be pretty close. Also, I don’t know how this would play with Swift, so I guess we could consider this an interesting piece of trivia from the Objective-C days and look for a better solution…
A second, also slightly hacky option that comes to mind is using the associated objects feature to link the cached data to the original instance. That way you could keep your extensions approach.
You created your own CustomRectangle(object: rect) , so swift will not provide default init() any more. You explicitly need to call one of your own holding your property and make call to super.init(), as your class also inherits from super class. –
class NativeRectangle: NSObject {
var width: Int
var height: Int
// Super class custom init()
init(width: Int, height: Int) {
self.width = width
self.height = height
super.init()
}
}
class CustomRectangle: NativeRectangle {
// computed property area
var area: Int { return width * height}
// Sub class Custom Init
init(object:NativeRectangle) {
// call to super to check proper initialization
super.init(width: object.width, height: object.height)
}
}
let rect = NativeRectangle(width: 100, height: 20)
let customRect = CustomRectangle(object: rect)
print(customRect.area) //2000
Related
What's the main difference between property observers and property wrappers? They seem to be very similar in that they manage how the properties are stored. The only thing I can think of is that you can reuse property wrappers since there is a layer of separation between code that manages how a property is stored and the code that defines a property.
Property Wrapper
#propertyWrapper
struct TwelveOrLess {
private var number: Int
init() { self.number = 0 }
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
struct Rectangle {
#TwelveOrLess var height: Int
#TwelveOrLess var width: Int
}
Property Observer
struct Rectangle {
var height: Int {
didSet {
if oldValue > 12 {
height = 12
} else {
height = oldValue
}
}
}
var width: Int {
didSet {
if oldValue > 12 {
width = 12
} else {
width = oldValue
}
}
}
}
The two cases above accomplish pretty much the same thing, which is to set the properties to be equal to or less than 12.
You say:
The only thing I can think of is that you can reuse property wrappers since there is a layer of separation between code that manages how a property is stored and the code that defines a property.
Your example (and some of your text) appears to be lifted from the Swift Programming Language: Property Wrapper manual:
A property wrapper adds a layer of separation between code that manages how a property is stored and the code that defines a property. For example, if you have properties that provide thread-safety checks or store their underlying data in a database, you have to write that code on every property. When you use a property wrapper, you write the management code once when you define the wrapper, and then reuse that management code by applying it to multiple properties.
So, yes, the virtue of the property wrapper is the reuse achieved by separating the “code that manages how a property is stored and the code that defines a property.” This resulting reuse is the whole m.o. of property wrappers.
You clearly, you can write your own setters and getters (which is better, IMHO, than a pattern of writing an observer that mutates itself), too, but you lose the reuse and abstraction that the property wrappers offer.
You go on to say:
The two cases above accomplish pretty much the same thing, which is to set the properties to be equal to or less than 12.
Sure, but if you want to do this for ten different properties, the wrapper avoids you from needing to repeat this code ten times. It also abstracts the details of this “equal to or less than 12” logic away from where you declare the property.
Another big difference betwixt property observers and property wrappers is that property observers can access self, whilst property wrappers cannot yet (as of this writing) access self using a stable, documented interface.
You can work around this limitation by manually passing self to the property wrapper in init. This workaround is described in the property wrapper proposal.
You can access self in a property wrapper using an undocumented, unstable interface which you can learn about by typing “property wrapper _enclosingInstance” into your favorite search engine.
In my app I need to add to a bunch of UIKit objects some properties; my original thought was to create a subclass of each element I needed and create the properties inside the new class but I realized that this means to write a new class for each UI element type I'm using.
In my specific case, I wanna add to some different views, such as UIImageView and UILabel, two properties called initial position and final position of type CGRect to store the initial and final position in order to use it inside a method which translates this views.
Is there any way to accomplish this without creating lots of classes?
You can do the following:
protocol Position {
var initialPosition: Int { get set }
}
It is not possible to just declare properties in extensions, so you'd need to set your get and set. You can just associate a value:
private var initialPositionKey: UInt = 0
extension Position {
var initialPosition: Int {
get {
return objc_getAssociatedObject(self, &initialPositionKey) as! Int
}
set {
objc_setAssociatedObject(self, &initialPositionKey, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}
}
Then you extend your UIView like this:
extension UIView: Position {}
And the following works:
var view = UIView()
view.initialPosition = 5
print (view.initialPosition) // 5
On whatever project you're currently working on, simply
On any screen drop in a UIView
Just add a width constraint (666 or whatever is fine),
Change the custom class of the constraint, to Constrainty
Run the app,
How can this possibly be?
Does it actually call for the value of the constant, "before the class is initialized," or some such?
How can it happen, and how to solve?
At first, I had the two variables as #IBInspectable and I was surprised that didn't work at all. But then I changed them to ordinary let constants - and that doesn't work!
class Constrainty: NSLayoutConstraint {
let percentageWidth: CGFloat = 77 // nothing up my sleeve
let limitWidth: CGFloat = 350
override var constant: CGFloat {
get { return teste() }
set { super.constant = newValue }
}
func teste()->CGFloat {
print("\n\n HERE WE GO \(percentageWidth) \(limitWidth) \n\n")
if let sw = (firstItem as? UIView)?.superview?.bounds.width {
let w = sw * ( percentageWidth / 100.0 )
let r = w > limitWidth ? limitWidth : w
print("result is \(r) \n\n")
return r
}
return 50
}
}
I don't think it's a good idea to subclass NSLayoutConstraint. I don't think it was designed to be subclassed outside of Apple.
Anyway, the problem is that NSLayoutConstraint conforms to the NSCoding protocol, but doesn't declare that it conforms to NSCoding in the header files. Because of this, Swift doesn't know that NSLayoutConstraint can be initialized by -[NSLayoutConstraint initWithCoder:], so it doesn't generate an override of initWithCoder: that initializes the instance variables you add in your subclass.
Here's how to fix it.
First, if your project doesn't have a bridging header, add one. The easiest way to add one is to create a new Objective-C class in your project, accept Xcode's offer to create the bridging header, then delete the .h and .m files it created for the class (but keep the bridging header).
Then, in the bridging header, declare that NSLayoutConstraint conforms to NSCoding:
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import UIKit;
#interface NSLayoutConstraint (MyProject) <NSCoding>
#end
Finally, in your Constrainty class, override init(coder:) like this:
required init(coder decoder: NSCoder) {
super.init(coder: decoder)!
}
Et voila:
HERE WE GO 77.0 350.0
result is 246.4
My wild guess it's all because of a class named UIClassSwapper. It's a private class that handles all the UI objects initialization from the Interface Builder files. I would suggest to replace your let constants with computed properties.
//...
var percentageWidht: CGFloat { // nothing up my sleeve
return 77.0
}
var limitWidth: CGFloat {
return 110.0
}
//...
UPD
Swift default property values(properties with values in their declaration) are being set before the initializer call. E.G. if you have a class MyClass with a property let someVar: CGFloat = 12.0 and it's bridged to Objective-C, when you allocate memory for your object and do not call an initializer MyClass *obj = [MyClass alloc] your variable will have a default value of 0.0 and will stay so unless you’ll call an initializer like [obj init]. So my second wild guess is that because NSLayoutConstraint class is written in Objective-C and it's initWithCoder: initializer isn't declared in it's header(it's private), the ObjC-Swift bridging mechanism doesn't recognize it's call as an initializer call(it thinks it is just a simple instance method), so your Swift properties with default values aren't being initialized at all.
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
I would like to create a method like this for my projects:
func print(obj: AnyObject) {
if let rect = obj as? CGRect {
println(NSStringFromCGRect(rect))
}
else if let size = obj as? CGSize {
println(NSStringFromCGSize(size))
}
//...
}
But I can't because CGRect and CGSize are structs and do not conform to the AnyObject protocol. So, any ideas on how this could be done?
Use Any instead of AnyObject.
Swift provides two special type aliases for working with non-specific
types:
• AnyObject can represent an instance of any class type.
• Any can represent an instance of any type at all, including function types.
The Swift Programming Language
#nkukushkin's answer is correct, however, if what you want is a function that behaves differently depending on whether it’s passed a CGRect or a CGStruct, you are better off with overloading:
func print(rect: CGRect) {
println(NSStringFromCGRect(rect))
}
func print(size: CGSize) {
println(NSStringFromCGSize(size))
}
In comparison, the Any will be both inefficient (converting your structs to Any and back, could have a big impact if you do this a lot in a tight loop), and non-typesafe (you can pass anything into that function, and it will only fail at runtime).
If your intention is to coerce both types into a common type and then do the same operation on it, you can create a 3rd overload that takes that type, and have the other two call it.
Just discovered a much better method of doing this. Swift has a method called dump, and it works with a lot of kinds of data.
For example:
dump(CGRectMake(0, 5, 30, 60))
Will print:
{x 0 y 5 w 30 h 60}
If you just need to print a CGRect or CGSize, you could use:
println(rect)
or
println(size)
You left a '...' at the end of your function so I assume there are more types that you need to print. To do that you need to make those types conform to the Printable protocol (unless they already do). Here's an example of how -
class Car {
var mileage = 0
}
extension Car : Printable {
var description: String {
return "A car that has travelled \(mileage) miles."
}
}
The you can use:
let myCar = Car()
println(myCar)
Also, you may want to change the format of the way a type is currently printed. For example, if you wanted println(aRect) in the same format as returned by NSStringFromCGRect you could use the extension:
extension CGRect : Printable {
public var description: String {
return "{\(origin.x), \(origin.y)}, {\(size.width), \(size.height)}"
}
}