I'll keep it short. I'm trying to accomplish the following:
class Media {
var likes.count : Int? = 0
}
Obviously the complier throws me an error:
Consecutive declarations on a line must be separated by ';'
Is there a way to work around this? I know that i can eventually do some kind of String Replace using Mirror(reflecting:object) but i'd like to keep it efficient. Would love any help. Thanks.
UPDATE:
I wasn't clear enough, sorry. The issue is that the complier won't let me use . inside the variable declaration name.
The issue is that the complier won't let me use . inside the variable declaration name.
Exactly, a property name in Swift cannot contain the . character.
A possible approach
Now, if you want to be able to write something like this
let media = Media()
media.likes.count = 1
then you need to define your class like shown below
class Media {
class Likes {
var count = 0
}
var likes = Likes()
}
or
class Likes {
var count = 0
}
class Media {
var likes = Likes()
}
A few suggestions
PLEASE don't use implicitly unwrapped optionals like this one
var likes.count : Int! = 0
They are like a gun ready to fire and crash your entire app!
And finally the class keyword begins with a lowercase character: class not Class.
I recommend using a Struct. A Struct is basically the same as a class that is referenced by value. So you can have as many Structs as you want with their own nested variables and functions, just like a class! And the best part is, you never have to use the Struct as a functional piece of code, just as something to namespace your variables in. I do this frequently with a Constants swift file.
struct Constants {
struct MainMenu {
static var height:CGFloat = 420
static var width:CGFloat = 240
static var backgroundColor:UIColor = .red
}
struct MainViewController {
static var toolBarHeight:CGFloat = 49
static var backgroundColor:UIColor = .blue
}
}
Usage:
func getRemainingHeight() ->CGFloat {
let viewHeight = self.view.bounds.size.height
let menuHeight = Constants.MainMenu.height
let toolBarHeight = Constants.MainViewController.toolBarHeight
return viewHeight - (menuHeight + toolBarHeight)
}
Related
I drank the struct/value koolaid in Swift. And now I have an interesting problem I don't know how to solve. I have a struct which is a container, e.g.
struct Foo {
var bars:[Bar]
}
As I make edits to this, I create copies so that I can keep an undo stack. So far so good. Just like the good tutorials showed. There are some derived attributes that I use with this guy though:
struct Foo {
var bars:[Bar]
var derivedValue:Int {
...
}
}
In recent profiling, I noticed a) that the computation to compute derivedValue is kind of expensive/redundant b) not always necessary to compute in a variety of use cases.
In my classic OOP way, I would make this a memoizing/lazy variable. Basically, have it be nil until called upon, compute it once and store it, and return said result on future calls. Since I'm following a "make copies to edit" pattern, the invariant wouldn't be broken.
But I can't figure out how to apply this pattern if it is struct. I can do this:
struct Foo {
var bars:[Bar]
lazy var derivedValue:Int = self.computeDerivation()
}
which works, until the struct references that value itself, e.g.
struct Foo {
var bars:[Bar]
lazy var derivedValue:Int = self.computeDerivation()
fun anotherDerivedComputation() {
return self.derivedValue / 2
}
}
At this point, the compiler complains because anotherDerivedComputation is causing a change to the receiver and therefore needs to be marked mutating. That just feels wrong to make an accessor be marked mutating. But for grins, I try it, but that creates a new raft of problems. Now anywhere where I have an expression like
XCTAssertEqaul(foo.anotherDerivedComputation(), 20)
the compiler complains because a parameter is implicitly a non mutating let value, not a var.
Is there a pattern I'm missing for having a struct with a deferred/lazy/cached member?
Memoization doesn't happen inside the struct. The way to memoize is to store a dictionary off in some separate space. The key is whatever goes into deriving the value and the value is the value, calculated once. You could make it a static of the struct type, just as a way of namespacing it.
struct S {
static var memo = [Int:Int]()
var i : Int
var square : Int {
if let result = S.memo[i] {return result}
print("calculating")
let newresult = i*i // pretend that's expensive
S.memo[i] = newresult
return newresult
}
}
var s = S(i:2)
s.square // calculating
s = S(i:2)
s.square // [nothing]
s = S(i:3)
s.square // calculating
The only way I know to make this work is to wrap the lazy member in a class. That way, the struct containing the reference to the object can remain immutable while the object itself can be mutated.
I wrote a blog post about this topic a few years ago: Lazy Properties in Structs. It goes into a lot more detail on the specifics and suggest two different approaches for the design of the wrapper class, depending on whether the lazy member needs instance information from the struct to compute the cached value or not.
I generalized the problem to a simpler one: An x,y Point struct, that wants to lazily compute/cache the value for r(adius). I went with the ref wrapper around a block closure and came up with the following. I call it a "Once" block.
import Foundation
class Once<Input,Output> {
let block:(Input)->Output
private var cache:Output? = nil
init(_ block:#escaping (Input)->Output) {
self.block = block
}
func once(_ input:Input) -> Output {
if self.cache == nil {
self.cache = self.block(input)
}
return self.cache!
}
}
struct Point {
let x:Float
let y:Float
private let rOnce:Once<Point,Float> = Once {myself in myself.computeRadius()}
init(x:Float, y:Float) {
self.x = x
self.y = y
}
var r:Float {
return self.rOnce.once(self)
}
func computeRadius() -> Float {
return sqrtf((self.x * self.x) + (self.y * self.y))
}
}
let p = Point(x: 30, y: 40)
print("p.r \(p.r)")
I made the choice to have the OnceBlock take an input, because otherwise initializing it as a function that has a reference to self is a pain because self doesn't exist yet at initialization, so it was easier to just defer that linkage to the cache/call site (the var r:Float)
I am using struct in swift.
class Constants {
struct const {
static let signupFirstName = "signupFirstName"
}
}
I want to iterate the struct. For iterating I am using :
let mirrored_object = Mirror(reflecting: Constants.const())
for (index, attr) in mirrored_object.children.enumerate() {
if let property_name = attr.label as String! {
print("Attr \(index): \(property_name) = \(attr.value)")
}
}
But it does not enter into the code because of static value. Is there any way to iterate this struct?
Since static members are technically part of the type and not the instance, you would need to approach it this way to reflect on the type itself:
let mirrored_object = Mirror(reflecting: Constants.const.self)
However, Swift's automatic reflection for types themselves doesn't appear to be implemented at this time, so even the above line won't work.
That leaves one last option, which is defining your own custom mirror for reflecting on an instance of your type. That could look something like this:
class Constants {
struct const : CustomReflectable {
static let signupFirstName = "signupFirstName"
func customMirror() -> Mirror {
return Mirror(self, children: ["signupFirstName" : const.signupFirstName])
}
}
}
If you modify your code with a CustomReflectable implementation similar to the above, your loop to iterate through the struct members will now work.
Swift reflection will eventually get better out of the box, you might want to try a different approach until then.
You can do it directly by accessing the variable at class level
if let property_value = const.signupFirstName as String! {
print("hello \(property_value)")
}
Be sure to access it from the class it self const not an instance const(). Because the variable is static you can not access it from instance, you have to directly use the class
I have been updating my game recently to use more value types. I am still not 100% confident with weak and unowned in some cases so I went the struct way to avoid strong reference cycles. As per apples newer keynotes it seems value types are they way to go for the most part anyway.
I have never seen an example where structs are used to render sprites in a spriteKit game so I wonder what the drawbacks are.
I understand that they are copied and not referenced but for my usage it seems to work.
So basically is there something I need to watch out for when doing this
struct Flag {
let post: SKSpriteNode
let flag: SKSpriteNode
init(postImage: String, flagImage: String) {
post = SKSpriteNode(imageNamed: postImage)
// other set ups for post sprite
flag = SKSpriteNode(imageNamed: flagImage)
// other set ups for flag sprite
post.addChild(flag)
}
func animate() {
// code to animate flag
}
}
Than in my SKScenes I simply add them as usual
let flag = Flag(postImage: "FlagPostImage", flagImage: "FlagImage")
flag.post.position = ...
addChild(flag.post)
flag.animate()
Now even if I create multiple flags in the same scene I seem to have no problems with this way.
I am just curious because I have never really seen an example like this so I wonder if I am missing something, like performance drawbacks etc.
Thanks for any help.
Personally I avoid creating Structs that contain Classes. Because Structs copy, each and every copy that get's passed around your app will increase the reference count of the Classes. This makes it harder to manage them instead of easier.
It is also useful to take a look at how UIKit uses Structs. A UIView is an object but has many defining properties that are Structs. For example it's frame.
Drop the code below in a playground to see some effects of this behaviour.
The protocol is just to get some meaningful feedback form the playground.
protocol IDLookable : CustomPlaygroundQuickLookable {
var id : Int { get set }
}
extension IDLookable {
func customPlaygroundQuickLook() -> PlaygroundQuickLook {
return PlaygroundQuickLook.AttributedString(NSAttributedString(string: "\(self.dynamicType) with id : \(self.id)"))
}
}
class MyClass : IDLookable {
var id : Int = 0
init(id : Int) {
self.id = id
}
}
struct MyContainerStruct : IDLookable {
var id : Int = 0
var object : MyClass
init(id : Int, object:MyClass) {
self.id = id
self.object = object
}
}
class Scope {
// ref count = 1
var object = MyClass(id: 11)
var structContainer : MyContainerStruct
init() {
// ref count = 2
structContainer = MyContainerStruct(id: 222, object: object)
messWithAClassInAStruct()
}
func messWithAClassInAStruct() {
// ref count = 3
var structContainerTwo = structContainer
structContainerTwo.id = 333
structContainerTwo.object // 11
// altering the object in one struct will obvously update all references
structContainerTwo.object.id = 1
structContainer.object // 1
structContainerTwo.object // 1
}
}
let test = Scope()
One pattern that does make it easy to work with Reference Types in Value Types is to store them as weak optionals in the Value Types. This means that something will need to have a strong reference but chances are that some Class will be responsible for creating the Structs this is a good place to keep that strong reference.
struct MyContainerStruct : IDLookable {
var id : Int = 0
weak var object : MyClass?
init(id : Int, object:MyClass) {
self.id = id
self.object = object
}
}
class Scope {
// ref count = 1
var object = MyClass(id: 11)
var structContainer : MyContainerStruct
init() {
// ref count = 1
structContainer = MyContainerStruct(id: 222, object: object)
messWithAClassInAStruct()
}
func messWithAClassInAStruct() {
// ref count = 1
var structContainerTwo = structContainer
structContainerTwo.id = 333
structContainerTwo.object // 11
}
}
let test = Scope()
From reading it seems like the best advice for creating a singleton in Swift is to use static let like this:
struct GameManager {
static let defaultManager = GameManager()
var gameScore = 0
var saveState = 0
private init() {}
}
GameManager.defaultManager.gameScore = 1024 // Error
GameManager.defaultManager.saveState = 12 // Error
let score = GameManager.defaultManager.gameScore
let savedProgress = GameManager.defaultManager.saveState
Because the defaultManager is declared as a constant (with "let"), there is an error when I try to assign gameScore and saveState.
I'm running Xcode 7.0 beta 6 (7A192o) with Swift 2.0 (swiftlang-700.0.57.3 clang-700.0.72).
If I change the defaultManager to be declared as a variable (with "var"), will it no longer be considered a proper singleton?
If I change the GameManager to be declared as a class instead of a structure, then the code works as expected.
class GameManager {
static let defaultManager = GameManager()
var gameScore = 0
var saveState = 0
private init() {}
}
GameManager.defaultManager.gameScore = 1024 // No error, why?
GameManager.defaultManager.saveState = 12 // No error, why?
let score = GameManager.defaultManager.gameScore // 1,024
let savedProgress = GameManager.defaultManager.saveState // 12
Can you explain why the reference-type class is better for implementing the singleton than the value-type structure?
You can't really change it because on your struct you have a let constant named defaultManager. As you know already a struct is a copy type while a class is a pass by reference one. if you want to use it as a struct you will have to replace that let with var instead. Another take of this problem is to change the struct to a class that way you will be able to change the defaultManager value although it is declared as a let.
cheers
edit: The main difference in your code is that when you have a constant in a class and you change that constant you are actually referring to its address rather than its actual value.Same doesn't happen with a struct cause as a value type you can't do that call by reference thingy you do with class and so you are forced to have a constant(let) value that cannot be mutated. Change the let to var inside your struct and see the magic happen
What is the main difference between "static var" and "var" in Swift? Can someone explain this difference to me, possibly with a little example?
static var belongs to type itself while var belongs to instance (specific value that is of specific type) of type. For example:
struct Car {
static var numberOfWheels = 4
var plateNumber: String
}
Car.numberOfWheels = 3
let myCar = Car(plateNumber: "123456")
All cars has same amount of wheels. An you change it on type Car itself.
In order to change plate number you need to have instance of Car. For example, myCar.
I'll give you a very nice Swifty example based on this post. Though this is a bit more sophisticated.
Imagine you have a project in which you have 15 collectionViews in your app. For each you have to set the cellIdentifier & nibName. Do you really want to rewrite all code for your that 15 times?
There is a very POP solution to your problem:
Let's help ourselves by writing a protocol which returns a string version of our ClassName
protocol ReusableView: class {
static var defaultReuseIdentifier: String { get }
}
extension ReusableView where Self: UIView {
static var defaultReuseIdentifier: String {
return String(Self)
}
}
extension BookCell : ReusableView{
}
The same for the nibName of each custom cell you have created:
protocol NibLoadableView: class {
static var nibName: String { get }
}
extension NibLoadableView where Self: UIView {
static var nibName: String {
return String(Self)
}
}
extension BookCell: NibLoadableView {
}
so now where ever I need nibName I would just do
BookCell.nibName
And where ever I need cellIdentifier I would just do:
BookCell.defaultReuseIdentifier
Now specifically to your question. Do you think we need to change the cellIdentifier per each new instance of BookCell?! No! All cells of BookCell will have the same identifier. It's not something that would change per instance. As a result it's been made static
While I did answer your question, the solution to reducing the number of lines for the 15 collectionViews can still be significantly improved so do see the blog post linked.
That blog post has actually been turned into a video by NatashaTheRobot
A static var is property variable on a struct versus an instance of the struct. Note that static var can exist for an enum too.
Example:
struct MyStruct {
static var foo:Int = 0
var bar:Int
}
println("MyStruct.foo = \(MyStruct.foo)") // Prints out 0
MyStruct.foo = 10
println("MyStruct.foo = \(MyStruct.foo)") // Prints out 10
var myStructInstance = MyStruct(bar:12)
// bar is not
// println("MyStruct.bar = \(MyStruct.bar)")
println("myStructInstance = \(myStructInstance.bar)") // Prints out 12
Notice the difference? bar is defined on an instance of the struct. Whereas foo is defined on the struct itself.