How to use Generics to handle dictionaries and arrrays - ios

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

Related

How to pass realm.objects(SomeObject.self).filter() to a function that needs Results<Object>

This question is in conjunction with RealmSwift Cannot cast Results<SomeOjbect> to Results<Object>
I have a Realm Object like:
import RealmSwift
class SomeObject: Object
{
#objc dynamic var datetime = ""
#objc dynamic var city = 0
convenience init(city: Int, datetime: String)
{
self.init()
self.city = city
self.datetime = datetime
}
}
There is a framework: https://github.com/danielgindi/ChartsRealm, which pull data from Realm and draw charts. The framework is written in Swift, and can be used in Objc as well, so it combines RLMObject and Object types.
It has a function like:
public convenience init(results: Results<Object>?, xValueField: String?, yValueField: String, label: String?)
which takes Results<Object>?, however I cannot get my filter results as Results<Object> type. e.g.
realm.objects(SomeObject.self).filter("city=0")
it's Results<SomeObject>, and cannot be converted to Results<Object>, described in RealmSwift Cannot cast Results<SomeOjbect> to Results<Object>
How can I solve it?
Because the demo in ChartsRealm framework, it simply read all objects from Realm in + (RLMResults *)allObjectsInRealm:(RLMRealm *)realm;, but in real world, we usually need to filt the results first.
If there's really nothing I can do, I could accept modifying the framework function parameters, filing pull requests for the framework, just to make it work.
Results<Object> does not make any sense as a type, and the methods in ChartsRealm should be generic methods which take a Results<T>.
Because in this specific case all that ChartsRealm does with the Results<Object> is use ObjectiveCSupport.convert() to get a RLMResults, an unsafeBitCast() to Results<Object> should work fine. You could also just call ObjectiveCSupport.convert() yourself and pass ChartsRealm a RLMResults rather than a Swift Results object.

Instatiate Realm Object from string in swift 3

I would like to know if it is possible to instantiate a realm object based on a string that is the class name of the realm object but without knowing what that string will be until it is provided.
For example:
for(_, object) in json["AllObjects"]{
let objectType = self.getRealmObjectBasedOnString(type: className, params: object.stringValue)
self.objectList.append(objectType)
}
Here I go through a json that I get and want to create a realm object from each json object in the array. The problem is that this method will be called several times and each time the only thing that will change is the className variable. So I would like to keep this logic in only one method instead of creating several methods with same logic or a huge and complicated if else that determines the realm object to be created.
Here is getRealmObjectBasedOnString
func getRealmObjectBasedOnString(type: String, params: String) -> Object{
switch type {
case "classA":
return ClassA(JSONString: params)!
case "classB":
return ClassB(JSONString: params)!
default:
return DefaultClass(JSONString: params)!
}
}
Can someone explain why this does not work and whether it is possible to accomplish what I want?
You can use NSClassFromString to get Realm object type from string, but keep in mind that Swift uses modules for nemespacing, so you'll need to add your app's module name before your class name.
guard let objectType = NSClassFromString("YourAppModuleName.\(json["className")") else {
// handle unexpected class here
}
let objectList = realm.objects(objectType)

Declare an array of Int in Realm Swift

How can I declare an array of integers inside RLMObject?
Like :
dynamic var key:[Int]?
Gives the following error :
Terminating app due to uncaught exception 'RLMException', reason: ''NSArray' is not supported as an RLMObject property. All properties must be primitives, NSString, NSDate, NSData, RLMArray, or subclasses of RLMObject. See https://realm.io/docs/objc/latest/api/Classes/RLMObject.html for more information.'
Lists of primitives are not supported yet unfortunately. There is issue #1120 to track adding support for that. You'll find there some ideas how you can workaround that currently.
The easiest workaround is create a object to hold int values. Then the model to have a List of the object.
class Foo: Object {
let integerList = List<IntObject>() // Workaround
}
class IntObject: Object {
dynamic var value = 0
}
Fortunately arrays of primitive types are now supported in Realm 3.0 and above. (Oct 31 2017)
You can now store primitive types or their nullable counterparts (more specifically: booleans, integer and floating-point number types, strings, dates, and data) directly within RLMArrays or Lists. If you want to define a list of such primitive values you no longer need to define cumbersome single-field wrapper objects. Instead, you can just store the primitive values themselves!
class MyObject : Object {
#objc dynamic var myString: String = ""
let myIntArray = List<Int>()
}
Source: https://realm.io/blog/realm-cocoa-reaches-3-0/
The accepted offer is very costly in term of memory.
You might get a List of very big "n" of objects.
It's not a matter of right and wrong but I think it's good to write here a different workaround.
Another approach:
I decided to use a single string to represent an Int array.
In my Realm class I defined a variable:
dynamic var arrInt: String? = nil
And use it very easily:
let arrToSave = [0, 1, 33, 12232, 394]
<MY_CUSTOM_REALM_CLASS>.arrInt = arrToSave.map { String(describing: $0) }.joined(separator: ",")
And the way back:
let strFetched = <MY_CUSTOM_REALM_CLASS>.arrInt
let intArray = strFetched.components(separatedBy: ",").flatMap { Int($0) }
Will be happy to hear your feedback, as I think this approach is better.
As the error message states, you have to use RLMArray - or rather it's swift equivalent List.
See: Realm docs

Remove Custom Object From Array

I would like to remove a custom object of class A from an array [A]()
I am well aware that this is a well discussed question on SO however there doesn't seem to be a generic and authoritative answer to it, either for beginners or experts.
Example: I have a FriendRequest class with a few attributes.
When I accept a FriendRequest, it should be removed from friendRequestArray.
I'm looking for an answer that aggregates the most common methods and best practices; something along the lines of:
As of Swift 2.1, there are 3 ways to do this (...)
please don't use X as it is deprecated (...)
Y is the wrong way to do this" etc.
I'm not sure I understand the question, let's see.
FriendRequest
You have a FriendRequest class like this
class FriendRequest {
let id: String
init(id: String) {
self.id = id
}
}
Let's make it Equatable
extension FriendRequest: Equatable {}
func ==(left: FriendRequest, right: FriendRequest) -> Bool {
return left.id == right.id
}
requests
Now we create 3 FriendRequest(s)
let request0 = FriendRequest(id: "000")
let request1 = FriendRequest(id: "001")
let request2 = FriendRequest(id: "002")
and let's create the requests array
var requests = [request0, request1, request2]
Removing a request
Now let's say we want to remove request1. We need to find the index (if it does exists) and use it to remove an element of the array.
if let index = requests.indexOf(request1) {
requests.removeAtIndex(index)
}
That's it
requests // [{id "000"}, {id "002"}]
Done with Swift 2.1.1 and Xcode Playground 7.2.

Subclassing v.s. Protocols

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?

Resources