Subclassing v.s. Protocols - ios

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?

Related

Can #dynamicMemberLookup be used to call methods?

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.

How to use Generics to handle dictionaries and arrrays

I am new to using generics but as according to my requirement I need to use it.
I have like 10 apis in which
4 returns array of custom objects(like multiple Person object data([Person]))
4 returns simple a object(like Company object data(Company))
two return simple dictionary
so what I'm trying to do is to create a common Response class
class Response<T>: NSObject {
#objc var responseData = T
}
But it is giving error on this line.
How should I suppose to use it so that it fulfills the requirements.
first of all generics cannot be represented in objc. so you need to use only Swift
class Response<T> {
var responseData: T!
}
you can use then T like this:
let response = Response<[String]>()
so response.responseData will be an array of String

Swift compile time errors when using generics and accessing dictionary's values

Below I have a class, B, with a generic type and the generic type has a subclass type constraint. In a separate class, A, I create a dictionary property, values, with the key as String and value as B. Class A then has methods to return or set values in the dictionary such that the values are not constrained to a single type (they maintain their generic SomeType type which is a subclass of NSObject). However, this produces the following two errors noted inline below:
class A: NSObject {
var values = [String : B]()
func get<SomeType: NSObject>(key: String) -> B<SomeType>? {
// #1 Error on line below: cannot convert return expression of type 'B<NSObject>?' to return type 'B<SomeType>?'
return values[key]
}
func set<SomeType: NSObject>(key: String, value: B<SomeType>) {
// #2 Error on line below: cannot assign value of type 'B<SomeType>' to type 'B<NSObject>?'
values[key] = value
}
}
class B<SomeType: NSObject>: NSObject {
}
I've attempted various forms of declaring the values dictionary to tell the compiler that SomeType is a subclass of NSObject and everything is going to be ok, but have been unsuccessful. Similarly to this question, I'm a bit stumped because the methods define SomeType as a subclass of NSObject and therefore things appear to be type safe when setting and getting from values.
I could remove the generic types from the methods and instead force the type to be <NSObject>, but then I'd run into the same problem as noted here.
This may not be doing what you think it's doing:
var values = [String : B]()
This isn't really [String : B], it's [String : B<NSObject>]. (I'm actually kind of surprised that this is legal syntax; I'd be tempted to open a bugreport about that; B isn't a proper type in Swift.) You may realize this already, but it's the first important note.
The second important note is that generic types are not covariant in Swift. A Thing<Cat> is not a subtype of Thing<Animal>. There are some type-theory reasons for this, and there are some technical implementation reasons for this, but the important fact is that it's not possible in Swift.
If you need to hold a variety of B types, then you'll need to build a type eraser. In your case, the type eraser could possibly be B<NSObject> with something like this:
class B<SomeType: NSObject>: NSObject {
let value: SomeType
init(value: SomeType) {
self.value = value
}
func liftGeneric() -> B<NSObject> {
return B<NSObject>(value: value)
}
}
If you need to hold just one kind of B type, then make A generic as well.

Swift: Dictionary passed as parameter is always empty

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.

Swift. Is it possible to determining property time at runtime

I have the next problem:
I have a class which can contain some data of different type but the type of the data is not known at compile time.
It looks like this
class Data {
var dataType: PodDataType = PodDataType.None
var componentsCount: UInt32 = 0
var stride: UInt32 = 0
var data // the data type of this field is unknown until dataType property is initialized
}
And I have another class which have multiple Data instances it looks like this:
class Mesh {
var verticesCount: UInt32 = UInt32.max
var facesCount: UInt32 = UInt32.max
var UVWChannelsCount: UInt32 = UInt32.max
var vertexIndexes: Data?
var stripLength: UInt32 = UInt32.max
var stripsCount: UInt32 = UInt32.max
var vertex: Data?
var normals: Data?
var tangents: Data?
var binormals: Data?
// and so on ...
}
Every time I create an new object of Data it should contain different data type in its 'data' field. What is the best way to solve such issues?
My thoughts:
1) AbstractFactory pattern: I can create base class Data and many subclasses like DataInt, DataFloat etc. but this means that I need to create subclass for every supporting type (int32, int8 and 15 types more).
2) Generics: I can define Data like this class Data, but after that my Mesh class become dependent from the Data class because there is no way to define generic class without type parameter.
3) UnsafePointer I can store data using this pointer but I not sure will the data persist if the NSData object from which I read the info is deallocated. Also what about the performance type casting from UnsafePointer to actual type.
Any other practices of this situation are highly appreciated.
P.S. I am developing parser for Pod file which stores 3D graphics data.
POD File Format Specification can be found here as reference.
Why not using Any?:
class Data {
var dataType: PodDataType = PodDataType.None
var componentsCount: UInt32 = 0
var stride: UInt32 = 0
var data: Any?
}
But I think this is the good use case for enum with associated values:
enum PodData {
case Ints([Int])
case Floats([Float])
// ...
case None
}
The usual approach to this in Swift is to make a property for each type and just use one for each instance. Simple, safe, and very little redundancy.
The only other viable alternative is to find a data format that can describe all the data types you want, e.g. String. But you will have to invest time to engineer reliable conversions for reading and writing. There is obviously a price in efficiency you have to pay.
In my opinion you could make use of first and second approach combined.
Make use of Abstract Factory pattern with concrete class for primitive class with Generics. It will make your life a bit easier.
class BaseData {
}
class PrimitiveData<T> : BaseData {
}
class UserDefinedData : BaseData {
}

Resources