I have made a file called Constants.swift. Within this, I have made a class like so...
public class WebServices {
static let getMyPlants : String = "plant/getPlants"
static let getMyOrganizations: String = "organization/getOrganizations"
}
Now whenever, I use an api anywhere in my project, I do Webservices.getMyPlants.
Now I also have a base-url for each of the API's. That is mentioned below public class WebServices.... like so..
struct envDev {
var BASEURL : String = "http://api-proj-dev.ii.the-co.com/api/"
}
Now, the base-url for Webservices.getMyOrganizations is different. I want to use a condition within struct envDev that if I have selected Webservices.getMyOrganizations, then I can give a different BASEURL. Something like...
//The below code isn't right. I just wrote it to represent the kind of solution I wish to have.
struct envDev {
var BASEURL : String = "http://api-proj-dev.ii.the-co.com/api/"
if Webservices.getMyOrganizations {
var BASEURL : String = "http://my second base-url.."
}
}
EDIT 1 Giving below the signature of APIHelper
class APIHelper: NSObject {
var API: NSString
var json: NSString
var receivedJSON: NSString?
var arrResult: NSMutableArray = []
let esmatBaseUrl = AppDelegate().currentUser //This is given in AppDelegate as `var currentUser = envDev()`
()
EDIT 2 Inclusion of baseUrl computed property in APIHelper & the error.
class APIHelper: NSObject {
var API: NSString
var json: NSString
var receivedJSON: NSString?
var arrResult: NSMutableArray = []
let esmatBaseUrl = AppDelegate().currentUser //This is given in AppDelegate as `var currentUser = envDev()`
()
var baseUrl: String {
esmatBaseUrl.baseUrl(forApi: API as String) // Here I'm getting the error as `Value of type 'envDev' has no member 'baseUrl'`
}
envDev has no way of knowing what happens in APIHelper, so you need a way to pass in the API from APIHelper to envDev. This means that BASEURL should not be a property, but a method:
func baseUrl(forApi api: String) -> String {
switch api {
case WebServices.getMyPlants: return "some url"
case WebServices.getMyOrganizations: return "some other url"
default: fatalError()
}
}
Then in APIHelper, you can add a baseUrl computed property that calls the above method:
var baseUrl: String {
esmatBaseUrl.baseUrl(forApi: API as String)
}
This would mean that you need to change all occurrences of esmatBaseUrl.BASEURL in your existing code to just baseUrl.
Also, I would suggest not using NSString, NSArray, etc in Swift. You should their Swift counterparts: String and [T].
I understood your query. You want to create an ENUM for your server-environment's, instead of hard-coding baseUrl's you probably want to use ENUMS to select different environments, right.
So accordingly, I've created an ENUM for you to add different server-environments so it will be feasible for you to use it frequently every-where.
private enum ServerEnv: String {
case stage, prod, test, my_plants, my_organization
var domainValue: String {
switch self {
case .test, .my_plants: return "http://api-testing-proj-dev.ii.the-co.com/api/"
case .stage: return "http://api-staging-proj-dev.ii.the-co.com/api/"
case .prod: return "http://api-production-proj-dev.ii.the-co.com/api/"
case .my_organization: return "http://api-my_organization-proj-dev.ii.the-co.com/api/"
}
}
}
Example :
let baseUrl = ServerEnv.my_organization.domainValue
Output => baseURL = "http://api-my_organization-proj-dev.ii.the-co.com/api/"
let baseUrl = ServerEnv.my_plants.domainValue
Output => baseURL = "http://api-testing-proj-dev.ii.the-co.com/api/"
I hope, I've solved your query here.
Happy Coding :-)
Related
In swift 4.2 I am facing the problem while handling the two array objects, When I am removing objects from another array, the values are removed from the all the objects.
1) Below is my closure
func GetChatBotData(completion: #escaping (_ result: ChatV_1_Model) -> Void) {
var ChatBotData : ChatV_1_Model! = nil
ApiHelper.sharedSession.postLoacl("http://localhost:3000/posts/", postData: NSDictionary(), methodtype: Constant.API.httpGet) { (isError, data, errorDescription) in
DispatchQueue.main.async(execute: {
if isError == false {
ChatBotData = ChatV_1_Model.init(fromDictionary: data!)
completion(ChatBotData)
}
else {
//completion("Error to get result" as AnyObject)
completion(ChatBotData)
}
})
}
}
Now In my controller
var PKComponents = [Chatbot_V_1_DataModel]()
var ChatMessages = [Chatbot_V_1_DataModel]()
override func viewDidLoad() {
super.viewDidLoad()
GetChatBotData() {(result: ChatbotV_1_Model!) in
print("Call Plans: \(result!)")
self.PKComponents = result.data
self.ChatMessages = result.data
self.ChatMessages[0].component.removeAll()
}
In Viewdidload I am removing objects from self.ChatMessages array but it removes from all the objects like, PKComponents and result.data as well.
Note: I have seen the reference of the result is same as PKComponents and Chatmessages.
How to resolve this?
Here's the simplified example, where I can reproduce your problem:
class Component {
}
class SomeData {
var components: [Component]
init(components : [Component]) {
self.components = components
}
}
class Result {
var data: [SomeData]
init(data: [SomeData]) {
self.data = data
}
}
let someData = SomeData(components: [Component()])
let result = Result(data: [someData])
//problem begins here
let pkCompent = result.data
var chatMsgs = result.data
print(pkCompent[0].components.count)
chatMsgs[0].components.removeAll()
print(pkCompent[0].components.count)
Inorder to avoid the reference issue, convert SomeData to struct
struct SomeData {
var components: [Component]
init(components : [Component]) {
self.components = components
}
}
You have 2 suggestions.
1- Deep copy .
2- Use struct instead of class since its value type.
Incase of deep copy this is a simple example,
when you assign something to new instance use this way.
// Deep copy
var foo = Foo()
var otherFoo = Foo(foo)
rather than this.
var fee = foo // shallow copy still the same referance
Note: this is handled by swift you don't have to add any inits to the class.
component is what you are removing it from and not the Array to
be precise.
While arrays implementation in swift is using a Struct which is a
value type and not a Object type, what your array is holding, i.e
Object of Chatbot_V_1_DataModel might as well be a class thus, the
elements held in your array are references to object of type
Chatbot_V_1_DataModel.
the way you can work around this is by having Chatbot_V_1_DataModel
defined as a struct thus, a value type OR by making a deep copy of
you array and then using that copy in you closure as you modify it.
I am talking about something on these lines:
var copie = arr.map{$0.mutableCopy()}
better yet:
var PKComponents = [Chatbot_V_1_DataModel]()
var ChatMessages = [Chatbot_V_1_DataModel]()
override func viewDidLoad() {
super.viewDidLoad()
var copie = arr.map{$0.mutableCopy()} // use this copy now elsewhere!!!
GetChatBotData() {(result: ChatbotV_1_Model!) in
print("Call Plans: \(result!)")
self.PKComponents = result.data
self.ChatMessages = result.data
self.ChatMessages[0].component.removeAll()
}
This is the problem of deep copying. Either you write a complete initializer that copies everything and create a new object and use that instead of just assignment. Or use struct instead of class. But as a quick fix you can explicitly only copy the component array like this:
self.PKCOMPONENTS = results.data
self.PKCOMPONENTS.components = Array(results.data.components)
I'm trying to implement a ORM layer on top of Couchbase Lite iOS 2.0, now it did removed the CBLModel apis which make it a little bit difficult to use.
I'm using a Reflection lib and its Mappable protocol(which is renamed to ORMMappable in the following code) to simplify the mapping apis.
Here's the error message:
let t = Self.cast_id_type(type: link, obj: value)
Cannot invoke 'cast_id_type' with an argument list of type '(type: ORMMappable.Type, obj: Any?)'
Expected an argument list of type '(type: D.Type, obj: Any?)'
And here's the problematic code
typealias MappableDictionary = [String : Any]
class IDString<T:ORMMappable> : NSString{
func load_object(){
}
}
struct MapMeta{
var ignores : [String] = []
var mapping : [String:ORMMappable.Type] = [:]
}
protocol ORMMappable {
var id : NSString {get set}
static var _meta : MapMeta{get}
init(dictionary: MappableDictionary) throws
}
extension ORMMappable {
init() throws{
try self.init(dictionary: [:] as MappableDictionary)
}
static func cast_id_type<D:ORMMappable>(type: D.Type,obj: Any?) -> IDString<D>?{
if let o = obj as? IDString<D>{
return o
}
return nil
}
init(dictionary: MappableDictionary) throws {
self = try construct { property in
let meta = Self._meta
if let value = dictionary[property.key] {
if let type = property.type as? ORMMappable.Type, let value = value as? MappableDictionary {
return try type.init(dictionary: value)
}
else if let link = meta.mapping[property.key]
{
let t = Self.cast_id_type(type: link, obj: value)
print(link)
//return t
return nil
}
else {
return value
}
} else {
return nil
//throw Error.missingRequiredValue(key: property.key)
}
}
}
}
A example of usage is
struct TestObject : ORMMappable{
static var _meta: MapMeta{
return MapMeta(ignores: [], mapping: ["link_id":TestObject2.self])
}
var id : NSString
var name : String?
var age : Int?
var link_id : IDString<TestObject2>?
}
IDString is holder for a link to other ORMMappable compatible class, mapping maps from String(property name) to a ORMMappable compatible class, and cast_id_type does check the mapping and trying to cast from the pointer of value to the StringID object. The error itself makes me quite confused here,
static func cast_id_type<D:ORMMappable>(type: D.Type,obj: Any?) -> IDString<D>?
D should be a ORMMappable compatible class, where I give is a value of a [String:ORMMappable.Type], but it rises ORMMappable.Type is not D.Type, how does this comes from?
Also I'm looking forward if there any better ways to do ORM in swift, currently the code does working with dynamic object creation, but when comes with ORM relation, it really drove me nuts here, just looking for ways to manage it in a easier and more manageable ways, where currently it looks like there are not much functionalities to do meta programming, a lot of other ORM libs still using objc, which is much more easier(but boilerplate) on dynamic instance creation or class inspection.
Thanks very much for the help, any hints will be real appreciated :)
Removed all generics solved the problem, it won't inferred in runtime environment.
I have a Localization struct which helps to manage local keys.
struct Localization {
//Home
static let HomeHeader = "Home_Header"
static let HomeStatusActive = "Home_Status_Active"
static let HomeStatusDelayed = "Home_Status_Delayed"
}
Also, I have string extension which named as local to gives me the key from Localizable.strings file.
extension String {
var local : String {
return LocalizationManager.getLocalizedString(key: self)
}
}
So when I need to localization key I use it like this;
titleLabel.text = Localization.HomeHeader.local
My question; Is there a way to perform an extension to use on every constant of struct without calling .local every time?
Basically, I want to call as below;
titleLabel.text = Localization.HomeHeader
Thanks a lot.
To do minimal changes on what you have implemented till now. You could simply add local after string values.
struct Localization {
//Home
static let HomeHeader = "Home_Header".local
static let HomeStatusActive = "Home_Status_Active".local
static let HomeStatusDelayed = "Home_Status_Delayed".local
}
extension String {
var local : String {
return LocalizationManager.getLocalizedString(key: self)
}
}
Then you will be able to use it like:
titleLabel.text = Localization.HomeHeader
Please check below may be helpful to you
You can keep all your localised string in one place
struct ConstantsLocalized {
static var key_loading: String {
return "key_loading".localized()
}
static var key_placeholder_email: String {
return "key_placeholder_email".localized()
}
}
And you can access it with ConstantsLocalized.key_loading
EDIT
I need to add one more advantage with this method, If you have in app localisation means user can change language from app it self then it is the best solution because you can get localise string every time
Hope it is helpful
I am currently working on the Smashtag application which can be downloaded here: http://web.stanford.edu/class/cs193p/cgi-bin/drupal/
I have been following along with the iTunes U video (YouTube link: https://www.youtube.com/watch?v=ZIwaIEfPAh8&spfreload=10 ) and I can't get past the errors I have been getting.
Even after downloading the final copy of the app from the Stanford website I am seeing these Swift Compiler Errors still popping up.
It continues to say Cannot assign to 'parameters' in 'self'
Could this be from Xcode being updated to 6.3 after this Smashtag app learning course was released in February/March 2015?
I appreciate your help, not sure how to solve this at the moment.
private var twitterAccount: ACAccount?
public class TwitterRequest
{
public let requestType: String
public let parameters = Dictionary<String, String>()
// designated initializer
public init(_ requestType: String, _ parameters: Dictionary<String, String> = [:]) {
self.requestType = requestType
**self.parameters = parameters**
}
// convenience initializer for creating a TwitterRequest that is a search for Tweets
public convenience init(search: String, count: Int = 0, _ resultType: SearchResultType = .Mixed, _ region: CLCircularRegion? = nil) {
var parameters = [TwitterKey.Query : search]
if count > 0 {
parameters[TwitterKey.Count] = "\(count)"
}
switch resultType {
case .Recent: parameters[TwitterKey.ResultType] = TwitterKey.ResultTypeRecent
case .Popular: parameters[TwitterKey.ResultType] = TwitterKey.ResultTypePopular
default: break
}
if let geocode = region {
parameters[TwitterKey.Geocode] = "\(geocode.center.latitude),\(geocode.center.longitude),\(geocode.radius/1000.0)km"
}
self.init(TwitterKey.SearchForTweets, parameters)
}
public enum SearchResultType {
case Mixed
case Recent
case Popular
}
As of Swift 1.2, giving your constant variables an initial value (not in init) means they cannot be reassigned a value in init. Therefore, because you're setting an initial value of parameters to be an empty dictionary, you cannot give parameters a new value in init. To solve this change your code to:
public class TwitterRequest {
public let requestType: String
// Note - now we just define the type here.
public let parameters: Dictionary<String, String>
public init(_ requestType: String, _ parameters: Dictionary<String, String> = [:]) {
self.requestType = requestType
self.parameters = parameters
}
// Other stuff
}
Alternatively you could change parameters to be a var, as pointed out by #Thomas Kilian in his comment. However, if you're not going to change the values stored in parameters it makes more sense to declare it as let and use the code above.
How do you instantiate a type dynamically based upon a lookup value in a dictionary in Swift?
Hopefully this is useful to others. It took some research to figure this out. The goal is to avoid the anti-pattern of giant if or switch statements to create each object type from a value.
class NamedItem : CustomStringConvertible {
let name : String
required init() {
self.name = "Base"
}
init(name : String) {
self.name = name
}
var description : String { // implement Printable
return name
}
}
class File : NamedItem {
required init() {
super.init(name: "File")
}
}
class Folder : NamedItem {
required init() {
super.init(name: "Folder")
}
}
// using self to instantiate.
let y = Folder.self
"\(y.init())"
let z = File.self
"\(z.init())"
// now put it in a dictionary.
enum NamedItemType {
case folder
case file
}
var typeMap : [NamedItemType : NamedItem.Type] = [.folder : Folder.self,
.file : File.self]
let p = typeMap[.folder]
"\(p!.init())"
let q = typeMap[.file]
"\(q!.init())"
Interesting aspects:
use of "required" for initializers
use of .Type to get the type for the dictionary value.
use of .self to get the "class" that can be instantiated
use of () to instantiate the dynamic object.
use of Printable protocol to get implicit string values.
how to init using a non parameterized init and get the values from subclass initialization.
Updated to Swift 3.0 syntax