Not able to pass value to another class - ios

I want to append a certain "id" to an api. This is the initial portion of how I make the API call in my viewController..
func myAPICall() {
APIHelper(API: WebServices.getAllOrganizations as NSString, json: bodyStr as NSString,
methodType: Constants.Get_Method as NSString....)
}
Now, WebServices.getAllOrganizations is defined elsewhere, in a swift file like so...
public class WebServices {
static let getAllOrganizations: String = "organization/getAllOrganizationDetails
}
MY ATTEMPT TO PASS THE ID TO THE SWIFT FILE :
To pass the value, I assigned it to a global variable like so...
ArrayData.shared.plantIDForOrganization = Int("\(dic["id"]!)")!
And further, I changed my swift file to this...
public class WebServices {
static let getAllOrganizations: String = "organization/getAllOrganizationDetails/\(ArrayData.shared.plantIDForOrganization)"
}
But by doing this, the value is not properly passed to the API. A 0 is passed to the API instead of the actual id number.
What could be a more efficient way of passing value from my viewcontroller to the swift file..?

When is ArrayData.shared.plantIDForOrganization initialized, and when does WebServices.getAllOganizations get its value? Once the latter is set, it won't "react" to changes in plantIDForOrganization.
I suggest you change this to a computed property, like so:
public class WebServices {
static var getAllOrganizations: String {
return "organization/getAllOrganizationDetails/\(ArrayData.shared.plantIDForOrganization)"
}
}
Also, try to eliminate thos force-unwrapping from your code.

If you have to pass a parameter use a static method instead:
public class WebServices {
static func getAllOrganizations(id: String) -> String { "organization/getAllOrganizationDetails/\(id)" }
}

Related

common functions issues while converting code from objective c to swift

Currently I have been working on a task of converting code from objective c to swift. The work was going smooth until I occured with a common resuable code that works in objective c but I haven't getting any idea how should I do that in swift.
The scenario working in objective c is.
I have a common function in my dataManager class
- (void)saveRequest:(id)request forId:(NSNumber *)requestId {
WebRequest *requestData = [[WebRequest alloc] initWithEntity:[NSEntityDescription entityForName:WEB_REQUEST inManagedObjectContext:self.context] insertIntoManagedObjectContext:self.context];
requestData.data = [request toJSON];
requestData.requestId = requestId;
requestData.timestamp = [NSDate date];
[self save];
}
in my project the request classes are already created which contains the toJSON function.
from my controller according to user changes I created the request object and passes the request object to this function and this function calls the toJSON function in the request class and everything works in objective c.
But when I convert this function in swift then it didn't support id as function input variable and if I use Any in place of id then it gives an error that Any don't have any toJSON function.
As this function is common different request objects will come from different controllers.
I don't have any idea how should I go further from hear, If anyone have any idea please help me out
Your class should be like
class WebRequest:NSObject
{
var data :Data?
var requestId: NSNumber?
var timestamp: Date?
init(entity:String , insertIntoManagedObjectContext:NSManagedObjectContext)
{
//your code here
}
}
and your code will be as follows
func saveRequest(request:Request, requestId:NSNumber)
{
let requestData = WebRequest(entity: "entityName", insertIntoManagedObjectContext:self.context)
requestData.data = request.toJSON();
requestData.requestId = requestId;
requestData.timestamp = Date()
}
and Request class in which toJson() present
class Request: NSObject
{
//has some members
func toJSON()->Data
{
return Data()
}
}
There is an existing Swift protocol, Codable (or you can do just Encodable if you want, as Codable is merely Encodable and Decodable), which is designed explicitly for representing an object in JSON (or other formats).
You then use JSONEncoder (rather than JSONSerialization, for example) to encode the object into JSON. See Encoding and Decoding Custom Types:
Consider a Landmark structure that stores the name and founding year of a landmark:
struct Landmark {
var name: String
var foundingYear: Int
}
Adding Codable to the inheritance list for Landmark triggers an automatic conformance that satisfies all of the protocol requirements from Encodable and Decodable:
struct Landmark: Codable {
var name: String
var foundingYear: Int
}
You can then do:
let landmark = Landmark(name: "Big Ben", foundingYear: 1859)
do {
let data = try JSONEncoder().encode(landmark)
print(String(data: data, encoding: .utf8)!)
} catch {
print(error)
}
That will product JSON like so:
{
"name": "Big Ben",
"foundingYear": 1859
}
See that Encoding and Decoding Custom Types for more information.
But, if you make your types Codable/Encodable, you could then retire your toJSON method entirely. There’s no need to write code to encode JSON anymore.
If you’re looking for a more tactical edit to your project as you convert it from Objective-C to Swift, you could define your own protocol, say JsonRepresentable, that has a single method requirement, your toJSON (or to whatever you’ve renamed this method during your conversion process).
protocol JsonRepresentable {
func toJSON() -> Data
}
And then, for all of the types that have implemented this method, just add this conformance.
Ideally, go back to those individual files and move the method into an extension for that protocol, e.g., for your first object type:
extension RequestObject1: JsonRepresentable {
func toJSON() -> Data {
...
}
}
And for your second:
extension RequestObject2: JsonRepresentable {
func toJSON() -> Data {
...
}
}
Etc.
is not there a simpler way rather than changing it in whole project
I would suggest that the above is best, but, if you don’t want to go back to all of those individual type declarations, you can just add conformance with an empty extension right where you defined JsonRepresentable:
extension RequestObject1: JsonRepresentable { }
extension RequestObject2: JsonRepresentable { }
As long as those types have implemented that method, these extensions will let the compiler know about their conformance to your protocol.
Anyway, this method can then use this protocol:
func save(_ request: JsonRepresentable, requestId: Int) {
let requestData = ...
requestData.data = request.toJSON()
requestData.requestId = requestId
requestData.timestamp = Date()
save()
}

Can I initialize a Codable Model from a different model in a Swift extension?

I have a codable model
public final class MyCodableModel: Codable {
public let id: Int
}
I also have another model that happens to have the same variables inside it.
public final class MyOtherModel {
public let id: Int
}
Now, I want to instantiate MyCodableModel using MyOtherModel in an extension. I don't want to modify MyCodableModel directly because of dependency issues.
I first tried to use a normal initializer in my extension, but it said I needed to use a convenience initializer, so then I ended up with this:
extension MyCodableModel {
convenience init?(myOtherModel: MyOtherModel) {
id = myOtherModel.id
}
}
But the error says 'let' property 'id' may not be initialized directly; use "self.init(...)" or "self = ..." instead. I assume this is because I'm not using the designated initializer of init(from: Decoder).
Is there another way to do this? Or will I not be able to convert MyOtherModel to a MyCodableModel?

Can we access overridden class function from the base class in swift?

Am stuck in a situation where I have a let variable declared & initialized in base class. I would need to pass a different enum in one of my other classes extending this base class.
So, I tried creating a class function in base class so that I can override and return a different enum type. But is there any way that I can access the extended class from base class ?
Created a sample code below to help explain:
class A {
var string: String {
get {
// Is it possible to refer to the class type dynamically here ?
// So that it would call B's printMessage
return A.printMessage("Hello")
}
}
class func printMessage(message: String) -> String {
return "You shall not pass !"
}
}
class B: A {
override class func printMessage(message:String) -> String {
return message + "World !"
}
}
let obj = B()
print(obj.string)
make it like this:
var string: String {
get {
// Is it possible to refer to the class type dynamically here ?
// So that it would call B's printMessage
return self.dynamicType.printMessage("Hello")
}
}

Where to put reusable functions in IOS Swift?

New to IOS programming but just wondering where is the best place to put functions that I would use throughout my code. For example, I want to write a few functions to perform a POST request to a web service and return a dictionary. Maybe another function to do some calculations. Is it best to create another .swift file and put all my functions there. And what would be a good name to give the file if so?
public func postRequest() -> [String:String] {
// do a post request and return post data
return ["someData" : "someData"]
}
The best way is to create a helper class with static functions, like this:
class Helper{
static func postRequest() -> [String:String] {
// do a post request and return post data
return ["someData" : "someData"]
}
}
Now every time you need to use postRequest you can just use like so: Helper.postRequest()
I usually create a separate class if I have functions that will be used by multiple classes, especially for the ones involving network operations.
If you just have separate functions that will be used, you can simply create static functions inside that class so it is easily accessible by other classes in a static way:
class DataController {
static func getData() -> [String:String] {
// do some operations
return ["someData" : "someData"]
}
}
let data = DataController.getData() // example
However, what often has been the case for me (especially if it involves more complicated operations) was that these network operations needed to establish an initial connection beforehand or required some initial setups, and they also performed asynchronous operations that needed to be controlled. If this is the case and you will often be calling such methods, you might want to create a singleton object that you could use throughout different classes and functions. This way, you could do the initial setup or establish an initial connection just once, and then do the rest as needed with the other functions, instead of doing them every time the function gets called.
Creating a singleton object is pretty simple in Swift:
class DataController {
static let sharedInstance = DataController() // singleton object
init() {
// do initial setup or establish an initial connection
}
func getData() -> [String:String] {
// do some operations
return ["someData" : "someData"]
}
}
let data = DataController.sharedInstance.getData() // example
For the name of the class, I usually name it something like DataController or DataHelper, but anything that makes sense as a "helper" class would work.
Hope this helps :)
For reusable functions it depends what I decide to use. For this specific case I use a separate file, because posting to a backend will become more complicated when the application evolves. In my app I use a backend class, with all kinds of helper classes:
struct BackendError {
var message : String
}
struct SuccessCall {
var json : JSON
var containsError : Bool {
if let error = json["error"].string {
return true
}
else {
return false
}
}
}
typealias FailureBlock = (BackendError) -> Void
typealias SuccessBlock = (SuccessCall) -> Void
typealias AlamoFireRequest = (path: String, method: Alamofire.Method, data: [String:String]) -> Request
typealias GetFunction = (path: String , data: [String : String], failureBlock: FailureBlock, successBlock: SuccessBlock) -> Void
class Backend {
func getRequestToBackend (token: String )(path: String , data: [String : String], failureBlock: FailureBlock, successBlock:
}
For other cases I often use extensions on Swift classes. Like for getting a random element from an Array.
extension Array {
func sampleItem() -> T {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
This very old question but I would like to chirp some more points.
There are a few option, basically you can write your utility functions in Swift -
A class with static function. For example
class CommonUtility {
static func someTask() {
}
}
// uses
CommonUtility.someTask()
Also, you can have class method's as well instead of static method but those functions can be overridden by subclasses unlike static functions.
class CommonUtility {
class func someTask() {
}
}
// uses
CommonUtility.someTask()
Secondly, you can have Global functions as well, that are not part of any class and can be access anywhere from your app just by name.
func someTask() {
}
Though, selecting one over other is very subjective and I thing this is ok to make a class with static function in this particular case, where you need to achieve networking functionality but if you have some functions which perform only one task than Global function is a way to go because Global functions are more modular and separate out single tasks for a single function.
In case of static functions, if we access one of the static member, entire class gets loaded in memory. But in case of global function, only that particular function will be loaded in mem
You can create a separate swift class, might name it WebServicesManager.swift, and write all methods related to web requests in it.
You can use class methods, or singleton pattern to access the methods.

Grails : Overriding getter method in domain class

I can't override grails getter method and becoming crazy.
What I want is use a double value and a string value to get a formatted data, but when I'm typing my override method into String, the double value is null and when into double, it obviously get me an error because a String is returned !
I get a domain class like that :
class Project {
...
String currency
Double initialTargetAmount
...
}
First Override method (initialTargetAmount is null in this case) :
//#Override Comment or uncomment it does not make any change to the behaviour
public String getInitialTargetAmount() {
println "${initialTargetAmount} ${currency}" // display "null EUR"
"${initialTargetAmount} ${currency}" // initialTargetAmount is null
}
Second method :
//#Override Comment or uncomment it does not make any change to the behaviour
public Double getInitialTargetAmount() {
println "${initialTargetAmount} ${currency}" // display "1000.00 EUR"
"${initialTargetAmount} ${currency}" // Error : String given, Double expected
}
Any help is welcome.
Snite
Groovy has dynamic getters and setters.
So, initalTargetAmount field "creates" automatically a Double getInitialTargetAmount method. Which is why it works when you have the Double return Type. But when you set String, getInitialTargetAmount automatically refers to a field String initalTargetAmount which doesn't exist
Try changing the name of the method, for example getInitialAmountWithCurrency() and it will work. Maybe your best bet will be to override toString() method ^^
Your getter should be always the same type of your field, and it's noot a good approach to change the getter like this, because Grails (Hibernate internally) will understand that your object instance changed and will try to update it ( it will check the old and new values).
You're trying in fact is to have a String representation of your amount, so you have a couple of options to this:
1 - A new method
Creating a new method that returns String will not interfere in the hibernate flow and you can use it anywere.
class Project {
...
String currency
Double initialTargetAmount
...
String displayTargetAmount() {
"${initialTargetAmount} ${currency}"
}
}
2 - TagLib
Depending on your needs, you could create a TagLib to make this custom representations of your class. This can include html formatting.
class ProjectTagLib {
static namespace = "proj"
def displayAmount = { attrs ->
if(!attrs.project) {
throwTagErrro("Attribute project must be defined.")
}
Project project = attrs.remove('project')
//just an example of html
out << "<p>${project.initialTargetAmount} , ${project.currency}</p>"
}
}

Resources