Swift optional parameter functions - ios

So I have the following function:
func remoteCall(_url:String, _params:[String: String]?=nil){
...
...
Alamofire.request(.POST, _url, parameters: _params) //requires _params to be of type [String String!]
...
}
As you can see, I can do:
let url = "https://eamorr.com/remote.php"
remoteCall(url) //works great!
Or, I can do:
let url = "https://eamorr.com/remote.php"
let params = [
"email": "eamorr#eamorr.com",
"pword": "secret"
]
remoteCall(url, _params:params) //works great!
However, what I can't do is:
let url = "https://eamorr.com/remote.php"
let params = [
"email": email.text, //where "email" is a UITextField
"pword": pword.text //where "pword" is a UITextField
]
remoteCall(url, _params:params) //this doesn't work
I get this error:
'String!' is not identical to 'String'
I need to be able to accomodate all three situations (pass nothing, pass raw strings, and pass UITextField values)
Unfortunately, if I try to change the function signature (note the '!' after the keyword "String") to:
func remoteCall(_url:String, _params:[String: String!]?=nil){
...
...
}
The UITextField values work, passing nil works, but the raw strings situation fails at run-time.
fatal error: can't unsafeBitCast between types of different sizes
EXC_BAD_INSTRUCTION
I'll be using this function a lot, so I would like not to have to wrap my "params" variable up in messy code.
I'm new to Swift, an Objective-C head, and trying to re-learn everything again...
I guess if I can somehow convert any incorrect [String: String] to [String: String!] neatly inside the function without disturbing any nil's or [String: String!]'s that already work?

I think this should work:
let url = "https://eamorr.com/remote.php"
let params: [String: String] = [ // Note explicitly declared type
"email": email.text, //where "email" is a UITextField
"pword": pword.text //where "pword" is a UITextField
]
remoteCall(url, _params:params)
Problem in your case was that without explicit type declaration Swift will infer one for you. Both values in the dictionary you create are of String! type, which is different from String. Hence the error. If you explicitly tell Swift that params is of [String: String] type that should work fine because it is ok to assign String! value to a String variable.

Related

When i use UserDefaults.standard.object in Alamofire it shows "Extra argument in call" error

When I Use the Alamofire Function With Some CoreData Like UserDefaulfts.standard.object then the xcode will Throws an Error Extra Argument in call i tried approx all the Ans from Stackoverflow Like HTTPMethod and .JSONEncoding but not Happening
func Sync(){
let url = "http://abcd.com/reportlist"
let parameters = ["sort_by":"month_year",
"start":"1",
"end":"10"]
let key2 = UserDefaults.standard.object(forKey: "accessToken")
let headers = [
"Authorization": key2,
"Content-Type": "application/x-www-form-urlencoded"]
Alamofire.request(url, method: .post, parameters: parameters, headers: headers).responseJSON { response in
if response.result.isSuccess
{
var dictVal = response.result.value
let data1 = response.data
.................
Hold option key and press object(forKey function to read documentation hint. You will see that return type of that function is optional since nothing can be stored under the key you pass, right? So your key2 constant also is of Optional type.
Then when you use it in dictionary, headers itself becomes of type "String: Optional(String)" as one of values is Optional (key2).
Alamofire expects [String: String] dictionary type in headers parameter and since the type of your headers dict does not match it generates this error - extra argument. Like I don't know why you pass it to me I do not expect anything of type like that
That is it
So you either use string(forKey method which will return empty string in case nothing is stored under the key passed, or provide default value like that
let key2 = (UserDefaults.standard.object(forKey: "accessToken") as? String) ?? "defaultAccessTokenOrNothing" which has the same result as first suggestion
the Key used here is a String Type and in Header passing, u did not Mention the type of variable in a header
before I used this
let key2:String = UserDefaults.standard.object(forKey: "accessToken") as! String
xcode is again Happy to Code...

swift 3, JSON, invalid top-level type when writing

I have two exactly json objects, one is created from a function, the other is hard-coded, the hardcoded one works, the other doesn't (it always complains about the error invalid top-level type , which is weird. Any tip? Tks
let myData = self.dailyMileage?.toDictionary()
let directData = ["orgId" : self.orgId, "driverId" : self.driverId, "date" : Utils.getTodaysDate() ] as [String : Any]
//this won't work unless I substitute myData with directData
let jsonData = try JSONSerialization.data(withJSONObject: myData, options: .prettyPrinted)
//this is the function that produces myData, and nothing is nil
public func toDictionary() -> [String : Any] {
let dict = [ "orgId" : orgId , "driverId": driverId, "date" : date] as [String : Any]
return dict
}
JSONSerialization as given in the documentation:
An object that may be converted to JSON must have the following properties:
The top level object is an NSArray or NSDictionary. All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
All dictionary keys are instances of NSString. Numbers are not NaN or infinity.
Other rules may apply. Calling isValidJSONObject(_:) or attempting a conversion are the definitive ways to tell if a given object can be converted to JSON data.
I think the one that's coming from the function might have an NSDate object instead of an NSString object.
The other reason is because your myData object is optional. JSONSerialization may give an error like that is the object is optional.
Please check if it is due to one of those two reasons. Feel free to suggest edits to make it better.

Cannot assign value of type String to type AnyObject? Swift 3.0

I am suddenly getting this error for a dictionary of type:
var parameters = [String: AnyObject]()
and then if I try:
parameters["cancelled_by"] = someUser ?? ""
I am getting the error as :
Cannot assign value of type String to type AnyObject?
This is for Swift 3.0. What am I doing wrong here? Why doesn't it work?
String is the value type. AnyObject only accepts reference types. So in order to add both value types and reference types in Dictionary use Any instead of AnyObject, i.e.
var parameters = [String: Any]()
This is an addition to Swift 3.0.
I'm starting with Swift 3 right now, a bit late... however, until Swift 2.2 some Swift value types were automatically bridged to the corresponding foundation reference types, such as String to NSString, Dictionary<> to NSDictionary, and so forth. It looks like this automatic bridging has been removed in Swift 3.
There are cases where turning a [String : AnyObject] into [String : Any] makes sense, in others it doesn't, depending on what you're doing. In my current case, where I need reference types, it doesn't.
So I am solving the problem by requesting an explicit bridging, by casting to AnyObject:
var dictionary: [String : AnyObject] = [:]
dictionary["valueType"] = "Value Type" // Error
dictionary["referenceType"] = "Reference Type" as AnyObject // OK
For reference:
let text = "Text"
let asAny = text as Any
let asAnyObject = text as AnyObject
let asNSString: NSString = text as NSString
type(of: text) // Prints String.Type
type(of: asAny) // Prints String.Type
type(of: asAnyObject) // Prints _NSContiguousString.Type
type(of: asNSString) // Prints _NSContiguousString.Type

“type of expression is ambiguous without more context” using struct property as dictionary key

I am getting and exception:
type of expression is ambiguous without more context
with following code:
struct Parameter {
static let Email = "email"
static let Password = "password"
static let IsFacebookUser = "isFacebookUser"
}
let parameters : [String : AnyObject] = [Parameter.Email : email, Parameter.Password : password, Parameter.IsFacebookUser : false]
It's not accepting bool type and I don't want to change my data type.
Is there any issue in this code?
Your email and password are optional variables, you need to provide non-nil values to dictionary and, hence, should unwrap them by using ! as suffix
Try this
let parameters : [String : AnyObject] = [Parameter.Email : email!, Parameter.Password : password!, Parameter.IsFacebookUser : false]
Alternatively, you can also do
email = emailTextField.text!
password = passwordTextField.text!
Also, replace your struct with enum.
enum Parameter: String {
case Email: "emailKey"
...
}
and then use Parameter.Email.rawValue while creating dictionary.
This type of error also comes when we pass the wrong parameters type to the struct object.

Binary operator '+' cannot be applied to two String operands

Hi i have a question about some code.
Okay, the problem is that i have some code that works in one function, but gives me an error in another function. The first code block is the function that it works in.
BTW, it is only one line:
#IBAction func searchPhotosByPhraseButtonTouchUp(sender: UIButton) {
if (!searchText.text.isEmpty) {
// 2: Replace spaces with +
var escapedSearchText:String = searchText.text.stringByReplacingOccurrencesOfString(" ", withString: "+")
// 3: API Method arguments
let methodArguments = [
"method": METHOD_NAME,
"api_key": API_KEY,
"text": escapedSearchText,
"format": FORMAT,
"nojsoncallback": NO_JSON_CALLBACK,
"extras": EXTRAS,
"safe_search": SAFE_SEARCH
]
// This line is the problem, if i make it in this function there is no problems
let urlString = BASE_URL + encodeParameters(params: methodArguments)
// 4: Call the Flickr API with these arguments
getImageFromFlickrBySearch(methodArguments)
}
else {
self.imageInfoLbl.text = "You did not write anything in the textfield"
}
}
So as you can see, in the code block above all is fine, but if i do it like this:
func getImageFromFlickrBySearch(methodArguments: [String: AnyObject]) {
// 5: Initialize session and url
...
// Here it gives me the error:
// Binary operator '+' cannot be applied to two String operands
let urlString = self.BASE_URL + encodeParameters(params: methodArguments)
...
}
I get a error.
I have removed the rest of the code from the second code block function for clarity.
I should probably say that BASE_URL is a constant.
The only difference of the functions, is that one is a #IBAction??
I'm not all too familiar with Swift but what could be causing your error is the methodArguments: [String: AnyObject]. In the function that works, Swift knows that all objects in the dictionary are String objects, but in the second function, their types are AnyObject.
If all of the key/value pairs are actually strings, change your parameter to methodArguments: [String: String] and see if that works.

Resources