I want to fill Dictionary via a method of which dictionary is one of the parameter. When I add a value to key, say 15, it always return 0 count when I try to access it second time with same key i.e. 15. Here's the code.
private static var showWidgetMap = Dictionary<Int, [BaseWidget]>()
private static var hideWidgetMap = Dictionary<Int, [BaseWidget]>()
static func initHandler()
{
let cloudWidget = CloudWidget()
cloudWidget.setType(CreatorConstants.CLOUD)
let property1 = [CreatorConstants.IMG_SRC: "cloud1", CreatorConstants.X_COORD: "100", CreatorConstants.Y_COORD: "450"]
cloudWidget.setPropery(property1)
addWidgetInLocalTimeList(15, widget: cloudWidget, delete: false)
let emojiWidget = CloudWidget()
emojiWidget.setType(CreatorConstants.EMOTICON)
let property2 = [CreatorConstants.IMG_SRC: "1", CreatorConstants.X_COORD: "100", CreatorConstants.Y_COORD: "550"]
emojiWidget.setPropery(property2)
addWidgetInLocalTimeList(15, widget: emojiWidget, delete: false)}
static func addWidgetInLocalTimeList(time_milisec: Int, widget: BaseWidget, delete: Bool)
{
if(delete)
{
checkAndAdd(hideWidgetMap, key: time_milisec, widget: widget);
}
else
{
checkAndAdd(showWidgetMap, key: time_milisec, widget: widget);
}
}
private static func checkAndAdd(var map: Dictionary<Int, [BaseWidget]>, key: Int, widget: BaseWidget)
{
print("map count is")
print(map.count)
if var val = map[key]
{
val.append(widget);
}
else
{
var temp: [BaseWidget] = [];
temp.append(widget);
map[key] = temp
print(map.count)
}
}
print(map.count) always returns 0.
You need to understand the difference between value types and reference types.
Value type variables are just values. For example, an array is a value type. It is just a value of "a bunch of stuff" *. On the other hand, reference types are references to values. For example, when you create a UIViewController, that variable actually stores a reference to the actual UIviewController *.
Don't really understand? Then it's analogy time! The variables and constants you create are children. The things you put in variables and constants are balloons.
There are two types of children, one type (value types) likes to hold balloons directly in their hands. The other type (reference types) likes to hold balloons using a string **.
When you pass a child to a method, depending on what type of child he is, different things will happen:
A value type child holds the balloon in his hands, so tightly that the method parameter can't take it away from him. So what can it do? It creates a copy of it! It then takes the copy to the method implementation let it do its thing.
A reference type, however, holds balloons using a string. The method parameter will tie another string to the balloon so the implementation can access it using the string. As a result, no copies of the balloon are created.
So what are you doing wrong here?
Since swift dictionaries are value types, when you pass a dictionary to a method, as I said above, it creates a copy! In the implementation, you are actually editing a copy of the dictionary, not the original one. That's why the original dictionary still has a count of 0.
What can you do?
Instead of marking the parameter with var, which is a very bad practice btw, you mark it with inout!
private static func checkAndAdd(inout map: Dictionary<Int, [BaseWidget]>, key: Int, widget: BaseWidget)
The inout modifier basically says
Hey parameter, next time you see a value type, just get a string and tie it to the balloon that the child is holding.
There is also another thing that you should do. That is you should change the way you call your method.
Instead of
checkAndAdd(showWidgetMap, key: time_milisec, widget: widget)
You write
checkAndAdd(&showWidgetMap, key: time_milisec, widget: widget)
And magically, it works!
Conclusion: Parameters are dumb. They aren't even smart enough to know when to tie a string. Be careful when you work with value types.
Footnotes * Assume it is not nil
** Not the String type, but an actual string.
Related
In the documentation for #dynamicMemberLookup it says,
Apply this attribute to a class, structure, enumeration, or protocol to enable members to be looked up by name at runtime.
If I'm not mistaken, instance methods are considered members of a struct / class. However, when I try to call a function dynamically I get an error saying:
Dynamic key path member lookup cannot refer to instance method foo()
To reproduce the problem:
struct Person {
var name: String
var age: Int
func greet() {
print("hello, my name is \(name)")
}
}
#dynamicMemberLookup
struct Wrapper {
var value: Person
subscript<T>(dynamicMember keypath: KeyPath<Person, T>) -> T {
value[keyPath: keypath]
}
}
let person = Person(name: "John Doe", age: 21)
let wrapper = Wrapper(value: person)
wrapper.greet() // << Error: Dynamic key path member lookup cannot refer to instance method `greet()`
// Or
let function = wrapper.greet // << Error: Dynamic key path member lookup cannot refer to instance method `greet()`
function()
How can I dynamically call greet() using #dynamicMemberLookup? Is there any way to achieve what I'm trying to do?
Thanks in advance!
No, dynamicMemberLookup does not work for methods. As the signature of the subscript suggests, it only works for things that can be represented as a KeyPath. Method calls cannot be part of a key path. :(
Key-Path Expression
A key-path expression refers to a property or subscript of a type.
The path consists of property names, subscripts, optional-chaining
expressions, and forced unwrapping expressions. Each of these key-path
components can be repeated as many times as needed, in any order.
At compile time, a key-path expression is replaced by an instance of
the KeyPath class.
I suspect the reason why it is called "dynamic member lookup" is because it also works with subscripts. The alternative of dynamicPropertyOrSubscriptLookup is rather a mouthful isn't it?
One rather hacky fix would be to change greet into a computed property:
var greet: () -> Void { {
print("hello, my name is \(name)")
} }
If greet has had parameters, you could also change it into a subscript, but I think that is an even uglier solution.
I want a method to set a value for an instance variable but I want to tell it which variable to set the value for each time I call the function.
var first: Key!
var second: Key!
func setKey(for selectedKey: Key) {
let key = // key selected from picker
selectedKey = key
}
func someWhereElse() {
setKey(for: first)
setKey(for: second)
}
Key is a class so it’s a reference type. Am I understanding reference mechanics right or is what I want a reference to the reference? (Some kind of C type pointer)
It should be
func setKey(for reference: inout Key!) {
let key = // key value you want to set
reference = key
}
Then you can invoke the method as following,
setKey(for: &yourKeyValue)
If you want to point the reference to class object's instance member
setKey(for: &(yourObject.yourVariable) )
According to your code, it will be
var first: Key!
var second: Key!
func setKey(for selectedKey: inout Key!) {
let key = // key selected from picker
selectedKey = key
}
func someWhereElse() {
setKey(for: &first)
setKey(for: &second)
}
Note the inout attribute in parameters. This is very much like pointer in C.
In your case, classes are like already pointing to some kind of memory block (* Key).
So, what you need is pointer to pointer (** Key).
This can be done with inout Key or UnsafeMutablePointer<Key>. As Swift doesn't encourage usage pointers, inout Key should be used for safety.
Note that if you want to point to Key!, it should be inout Key!.
If for Key, it should be inout Key.
Key and Key! are not the same.
If you want to work with Unsafe Swift, here is the code
func setKey(for reference: UnsafeMutablePointer<Key!>) {
let key = // key value you want to set
reference.pointee = key
}
then you can call it the same way as inout,
setKey(for: &yourValue)
One solution is make variable identifier in Key class.
Set
first.identifier = 1
second.identifier = 2
Check this value in setKey method to identify the instance variable
Second solution is in setKey method, check reference
if first === selectedKey {
// First Instance
} else if second === selectedKey {
// Second Instance
} else {
print("the two instances are not identical!")
}
If the class that contains the instance variable is not a subclass, you can have it inherit NSObject so that it contains the setValue(_ value: Any?, forKey: String) method. You can then set the value of an instance variable of an instance of said class with a string as the key.
As for your understanding of reference mechanics, you are right that first and second would be passed by reference. However, if you change the value of selectedKey, you are not changing the value of first or second, you are changing the reference. selectedKey holds the reference, so to change the value of the object it references, you must change its properties, for example selectedKey.value = key. Changing the value of selectedKey itself changes the reference, so the object it is referencing will not be changed.
Lets begin with the Class approach:
class LoginCredentials {
var id : String
init(userID:String) {
self.id = userID
}
}
then we will have the following:
class FacebookLoginCredentials : LoginCredentials {
var token : String
init(userID:String,userToken:String) {
self.token = userToken
super.init(userID: userID)
}}
And
class TwitterLoginCredentials : LoginCredentials {
var token : String
var secret : String
init(userID:String,userToken:String,secret : String) {
self.token = userToken
self.secret = secret
super.init(userID: userID)
}
}
The second Approach is the Protocol Oriented if I am not wrong
protocol LoginCredentials {
var id : String { get }
}
then we will have :
struct FacebookLoginCredentials : LoginCredentials {
var id: String
var token : String
init(userID:String,userToken:String) {
self.id = userID
self.token = userToken
}
}
And
struct TwitterLoginProfile : LoginCredentials {
var id: String
var token : String
var secret : String
init(userID:String,userToken:String,secret : String) {
self.token = userToken
self.secret = secret
self.id = userID
}
}
I just need to know which one is more Swift ?
Ultimately, neither of these approaches is "more Swift". In Swift, you will sometimes want to use inheritance and other times you will want to use protocols. The real decision point for these two approaches is:
Do you want value type semantics (structs and protocols) or do you want reference type semantics (classes and protocols). I usually default to value type semantics because they are safer but there are definitely circumstances where reference type semantics are important. You can read more about that here: Why Choose Struct over Class.
Either or is acceptable in swift.
Here is how you want to distinguish from the two.
When working with Protocols, you want to treat these as if they were blue prints for your objects.
Ballplayers must know what a ball is, so any person that wants to be a Ballplayer must know what a ball is.
You have a set of rules you want certain objects to follow, make a protocol.
If you want to make objects that have functionality, and you want the children to inherent this functionality, and then have more functionality, then do the inheret class structure.
Dad can throw a ball at 100MPH
Junior can throw a ball at 100MPH and throw a curve ball.
This would be done with a class, not protocol
Structure instances are always passed by value, and class instances are always passed by reference. This means that they are suited to different kinds of tasks. As you consider the data constructs and functionality that you need for a project, decide whether each data construct should be defined as a class or as a structure.
As a general guideline, consider creating a structure when one or more of these conditions apply:
The structure’s primary purpose is to encapsulate a few relatively simple data values.
It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure.
Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced.
The structure does not need to inherit properties or behavior from another existing type.
Examples of good candidates for structures include:
The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double.
A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int.
A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double.
In all other cases, define a class, and create instances of that class
to be managed and passed by reference. In practice, this means that
most custom data constructs should be classes, not structures.
Why Choose Struct Over Class?
I am quite new in Swift. And I create a class(for example):
class Fraction{
var a: Int
init(a:Int){
self.a = a
}
func toString() -> String{
return "\(self.a)"
}
}
and I also build a in other class function:
class func A_plusplus(f:Fraction){
f.a++
}
Then in the executive class I write:
var object = Fraction(a:10)
print("before run func = " + object.toString())
XXXclass.A_plusplus(object)
print("after ran func =" + object.toString() )
So the console output is
before run func = 10; after ran func =11
The question is how can I just send a copy of the "object" to keep its value which equal to 10
And if functions are always pass-by-reference, why we still need the keyword: "inout"
what does difference between A_plusplus(&object)//[if I make the parameter to be a inout parameter] and A_plusplus(object)
Universally, I don't want to use struct. Although this will solve my
problem exactly, I do pass-by-value rarely.So I don't want program's
copying processes slow my user's phone down :(
And It seems conforming the NSCopying protocol is a good option.But
I don't know how to implement the function:
func copyWithZone(zone:
NSZone)-> AnyObject? correctly
If your class is subclass of NSObject,better to use NSCopying
class Fraction:NSObject,NSCopying{
var a:Int
var b:NSString?
required init(a:Int){
self.a = a
}
func toString() -> String{
return "\(self.a)"
}
func copyWithZone(zone: NSZone) -> AnyObject {
let theCopy=self.dynamicType.init(a: self.a)
theCopy.b = self.b?.copy() as? NSString
return theCopy
}
}
class XXXclass{
class func A_plusplus(f:Fraction){
f.a++
f.b = "after"
}
}
var object = Fraction(a:10)
object.b = "before"
print("before run func = " + object.toString())
print(object.b!) //“Before”
XXXclass.A_plusplus(object.copy() as! Fraction)
print("after ran func =" + object.toString() )
print(object.b!)//“Before”
If it is just a common swift class,You have to create a copy method
class Fraction{
var a: Int
init(a:Int){
self.a = a
}
func toString() -> String{
return "\(self.a)"
}
func copy()->Fraction{
return Fraction(a: self.a)
}
}
class XXXclass{
class func A_plusplus(f:Fraction){
f.a++
}
}
var object = Fraction(a:10)
print("before run func = " + object.toString())
XXXclass.A_plusplus(object.copy())
print("after ran func =" + object.toString() )
To make it clear,you have to know that there are mainly two types in swift
Reference types. Like Class instance,function type
Value types,Like struct and others(Not class instance or function type)
If you pass in a Reference types,you pass in the copy of Reference,it still point to the original object.
If you pass in a Copy type,you pass in the copy of value,so it has nothing to do with the original value
Let us talk about inout,if you use it,it pass in the same object or value.It has effect on Value type
func add(inout input:Int){
input++
}
var a = 10
print(a)//10
add(&a)
print(a)//11
Swift has a new concept so called "struct"
You can define Fraction as struct (Not class)
And
struct Fraction{
...
}
var object = Fraction(a:10)
var object1 = object //then struct in swift is value type, so object1 is copy of object (not reference)
And if you use struct then try to use inout in A_plusplus function
Hope this will help you.
how can I just send a copy of the "object" to keep its value which equal to 10
In Swift classes and functions are always passed by reference. Structs, enums and primitive types are passed by value. See this answer.
You can't pass an object by value. You would have to manually copy it before passing it by reference (if that's what you really want).
Another way is to turn your class into a struct, since it would then be passed by value. However, keep in mind there a few other differences between classes and structs, and it might not necessarily be what you want.
And if functions are always pass-by-reference, why we still need the keyword: "inout"
According to the swift documentation, inout is used when
you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead.
So in practice with inout you can pass a value type (such as struct or primitive) by reference. You shouldn't really use this very often. Swift provides tuples, that could be used instead.
what does difference between A_plusplus(&object)//[if I make the parameter to be a inout parameter] and A_plusplus(object)
There is no difference for your A_plusplus function. In that function you don't modify the parameter f itself, you modify the f.a property.
The following example shows the effect of using inout when passing a class object. Both functions are the same, differing only in its parameter definition.
class Person {
var name: String
init(name: String) { self.name = name }
}
var me = Person(name: "Lennon") // Must be var to be passed as inout
// Normal object by reference with a var
func normalCall(var p: Person) {
// We sure are able to update p's properties,
// and they will be reflected back to me
p.name = "McCartney"
// Now p points to a new object different from me,
// changes won't be reflected back to me
p = Person(name: "Ringo")
}
// Inout object reference by value
func inoutCall(inout p: Person) {
// We still can update p's properties,
p.name = "McCartney"
// p is an alias to me, updates made will persist to me
p = Person(name: "Ringo")
}
print("\(me.name)") //--> Lennon
normalCall(me)
print("\(me.name)") //--> McCartney
inoutCall(&me)
print("\(me.name)") //--> Ringo
In normalCall p and me are different variables that happen to point to the same object. When you instantiate and assign a new object to p, they no longer refer to the same object. Hence, further changes to this new object will not be reflected back to me.
Stating that p is a var argument just means that its value can change throughout the function, it does not mean the new value will be assigned to what was passed as argument.
On the other hand, in inoutCall you can think of p and me as aliases. As such, assigning a new object to p is the exact same as assigning a new object to me. Any and every change to p is persisted in me after the function ends.
I am creating at launch Dictionaries with var because I will modify them later when user does something. Dictionaries are added inside an Array in a singleton class to be used in multiple places but I get the warning "Variable 'variableName' was never mutated, consider...."
in the place I am creating them
If I make them with let and when I get object form array to modify it if I take it from array with var, no crash, no warning, no nothing...
What is the explanation for this?
UPDATE:
My Singleton Class:
class Config {
static let sharedInstance = Config()
var array_shapes: Array<Dictionary<NSObject,AnyObject>> = Array()
func createInitialShapeArray(){
var avion = createShapeDictionaryFor("Avion", objectName: "Avion", badgeStatus: "0", shapeImageName: "shape_avion");
//.......more objects like avion
array_shapes = [avion,//.....the other objects];
}
func createShapeDictionaryFor(objectID:String, objectName:String, badgeStatus:String, shapeImageName:String) -> Dictionary<NSObject,AnyObject>{
var dict: Dictionary<NSObject,AnyObject> = [:]
dict["objectID"] = objectID
dict["objectName"] = objectName
dict["badgeStatus"] = badgeStatus
dict["shapeImageName"] = shapeImageName
return dict;
}
}
And when I am mutating dictionaries (In main class):
#IBAction func btnPressed_done(sender:UIButton){
pennyPincherGestureRecognizer.recognize();
screenShotMethod()
var dict = Config.sharedInstance.array_shapes[Config.sharedInstance.currentShapeIndex] as Dictionary<NSObject,AnyObject>
dict["badgeStatus"] = "1"
self.initNextShape()
}
var avion has the warning "Variable 'variableName' was never mutated, consider...."
It is not an error trough, it's a warning and I was curious if I could silence them or what can I do to make them dissappear
Facts
You are declaring avion as a local variable of the method createInitialShapeArray
You are not mutating avion in the scope where it is defined
avion is a Dictionary therefore a Struct (value type rules are applied)
Conclusion
There is no need to declare avion as a variable, it should be a constant.
Please note that where you write
array_shapes = [avion, ...]
you are creating a copy of avion (because it's a Dictionary).
So if you change the value inside array_shapes you are changing another value.
Therefore, at the end of the day, you are not mutating avion... and the compiler is right, it should be a constant.
Example
Please consider the following code
func foo() {
var dict = [1: "One"] // <-- Compiler warning
var anotherDict = dict
anotherDict[2] = "Two"
}
Here I am getting the same compiler warning
Variable 'dict' was never mutated; consider changing to 'let' constant
This happens because I am changing anotherDict that is not just another reference to the same value, it is actually a totally different value. This is the rule with Struct(s) and Enum(s) because they are Value Types.
Hope this helps.
In Swift arrays and dictionaries are declared as struct so when you pass them to other function or use them in assignments their value is copied and not passed as reference the same way it's done for classes, this means that when you pass avion to the append() function of your array you pass a copy of the dictionary so the original variable is never mutated.
The same things happens when you try to modify on dictionary in the array thus copying the dictionary of your interest in dict: you aren't modifying the array inside your shared instance but the local variable dict.