Swift "change an item in an array" Noobie in swift - swift

how can i change an item in an array (Cannot convert value of type 'Int' to expected argument type 'String')
var headersSend: HTTPHeaders = [
"changeMe": "none",
"Accept": "application/json"
]
headersSend[0] = "changeMe" : "Changed!" // <--- ? Cannot convert value of type 'Int' to expected argument type 'String'

headersSend is a dictionary, not an array. It stores key-value pairs, where key and value are both of type String.
Accessing through headersSend[0] means you want to change item at key 0. You have a compilation error because dictionary's key is not of type Int. You have to use String key instead.
That's the way we change value at specific key
dictionary[key] = newValue
In your case it would be
headersSend["changeMe"] = "Changed!"
I suggest you to read more about collection types here.

Related

Generic subscript with constraints on associated type leads to "Cannot subscript a value of type..."

Using Swift 4.2, I'm trying to write a generic system to get rid of strings as key of dictionaries to use enums instead.
Here is what I came with:
extension Dictionary where Key == String {
subscript<T : RawRepresentable>(key: T) -> Value? where T.RawValue == String {
get { return self[key.rawValue] }
set { self[key.rawValue] = newValue }
}
}
This compiles, and is destined to take any RawRepresentable type with a String raw value as key to the subscript for every Dictionary with String as key.
Unfortunately when I do the following, it does not compile:
enum MovieKey: String {
case movieId = "movie_id"
case movies = "movies"
}
var dic = [String:String]()
dic[key: MovieKey.movieId] = "abc123" // error
I get the following compilation error: Cannot subscript a value of type '[String : String]' with an index of type '(key: MovieKey)'
Except if I'm mistaken, dic is a Dictionary with String as key, and MovieKey is RawRepresentable and the raw value is String typed...
If someone can explain what I'm doing wrong, thanks in advance.
The issue is that you aren't using subscript correctly. You shouldn't be supplying any argument labels to the subscript call, simply supply the enum value.
dic[MovieKey.movieId] = "abc123" compiles just fine.

Why I get optional value if I didn't mark it as optional [duplicate]

class X {
static let global: [String:String] = [
"x":"x data",
"y":"y data",
"z":"z data"
]
func test(){
let type = "x"
var data:String = X.global[type]!
}
}
I'm getting the error: Value of optional type 'String?' not unwrapped.
Why do I need to use ! after X.global[type]? I'm not using any optional in my dictionary?
Edited:
Even if X.global[type] may not exist for the type, force unwrapping will still crash on runtime. A better approach may be:
if let valExist = X.global[type] {
}
but Xcode is giving me the wrong idea by hinting about optional type.
Dictionary accessor returns optional of its value type because it does not "know" run-time whether certain key is there in the dictionary or not. If it's present, then the associated value is returned, but if it's not then you get nil.
From the documentation:
You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type. If the dictionary contains a value for the requested key, the subscript returns an optional value containing the existing value for that key. Otherwise, the subscript returns nil...
In order to handle the situation properly you need to unwrap the returned optional.
There are several ways:
Option 1:
func test(){
let type = "x"
if var data = X.global[type] {
// Do something with data
}
}
Option 2:
func test(){
let type = "x"
guard var data = X.global[type] else {
// Handle missing value for "type", then either "return" or "break"
}
// Do something with data
}
Option 3:
func test(){
let type = "x"
var data = X.global[type] ?? "Default value for missing keys"
}
If we look at the Dictionary implementation, subscript is returning a ValueType as optional because it doesn't know if the key is exists or not:
//Reading a key that is not present in `self` yields `nil`.
//Writing `nil` as the value for a given key erases that key from `self`.
subscript (key: KeyType) -> ValueType?
So when we try to get a value from our Dictionary we get it as an optional from the subscript; that is we have to unwrap the optional to get the underlying object. As mentioned in earlier answers, option2 is preferred.
guard var data = X.global[type] else {
//key = 'type' doesn't exists
}
//key exists so do something with 'data'

Cannot convert value of type 'Int' to expected argument type '_?'

Note: I'm a rookie in Swift
I'm using Former.
I'm fetching data from a realm model.
let industries = realm.objects(Industry)
Then I try to define a list of InlinePickerItem from it:
$0.pickerItems = industries.map({ industry in
return InlinePickerItem(title: industry.name, value: industry.id)
})
But XCode keeps saying: Cannot convert value of type 'Int' to expected argument type '_?', pointing to industry.id.
Am I missing something? I don't know if the issue comes from Former or from something that I don't understand in Swift. For example, what kind of type is _??
UPDATE:
After #dfri comment, attempt was unsuccessful. From my small understanding of Swift, I get that Swift gets lost. So I extracted the initialisation of the list of InlinePickerItem from the closure.
let industries = realm.objects(Industry)
let inlinePickerItems = industries.map({ industry in
return InlinePickerItem(title: industry.name, displayTitle: nil, value: industry.id)
})
let catRow = InlinePickerRowFormer<ProfileLabelCell, String>(instantiateType: .Nib(nibName: "ProfileLabelCell")) {
$0.titleLabel.text = "CATEGORY".localized
}.configure {
$0.pickerItems = inlinePickerItems
}
The error is disappeared when calling InlinePickerItem(title: industry.name, displayTitle: nil, value: industry.id) but I get something new when assigning it to $0.pickerItems which now is:
Cannot assign value of type '[InlinePickerItem<Int>]' to type '[InlinePickerItem<String>]'
Hope this will provide you with some helpful hints.
Type mismatch when assigning array to different type array
After the re-factoring of your code (after "update") its now apparent what is the source of error.
Immutable catRow is of type InlinePickerRowFormer<ProfileLabelCell, String>. From the source of [InlinePickerRowFormer] we see the that the class and its property pickerItems is declared as follows
public class InlinePickerRowFormer<T: UITableViewCell, S where T: InlinePickerFormableRow>
: ... {
// ...
public var pickerItems: [InlinePickerItem<S>] = []
// ...
}
The key here is that for an instance InlinePickerRowFormer<T,S> its property pickerItems will be an array with elements of type InlinePickerItem<S>. In your example above S is String
let catRow = InlinePickerRowFormer<ProfileLabelCell, String>
/* |
S = String */
Hence pickerItems is an array of InlinePickerItem<String> instances.
You try, however, to append the immutable inlinePickerItems to pickerItems, which means you're trying to assign an array of InlinePickerItem<Int> instances to an array with elements of type InlinePickerItem<String>; naturally leading to a type mismatch.
You can solve this type mismatch by:
Setting your catRow immutable to be of type InlinePickerRowFormer<ProfileLabelCell, Int>.

Why do I still need to unwrap Swift dictionary value?

class X {
static let global: [String:String] = [
"x":"x data",
"y":"y data",
"z":"z data"
]
func test(){
let type = "x"
var data:String = X.global[type]!
}
}
I'm getting the error: Value of optional type 'String?' not unwrapped.
Why do I need to use ! after X.global[type]? I'm not using any optional in my dictionary?
Edited:
Even if X.global[type] may not exist for the type, force unwrapping will still crash on runtime. A better approach may be:
if let valExist = X.global[type] {
}
but Xcode is giving me the wrong idea by hinting about optional type.
Dictionary accessor returns optional of its value type because it does not "know" run-time whether certain key is there in the dictionary or not. If it's present, then the associated value is returned, but if it's not then you get nil.
From the documentation:
You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type. If the dictionary contains a value for the requested key, the subscript returns an optional value containing the existing value for that key. Otherwise, the subscript returns nil...
In order to handle the situation properly you need to unwrap the returned optional.
There are several ways:
Option 1:
func test(){
let type = "x"
if var data = X.global[type] {
// Do something with data
}
}
Option 2:
func test(){
let type = "x"
guard var data = X.global[type] else {
// Handle missing value for "type", then either "return" or "break"
}
// Do something with data
}
Option 3:
func test(){
let type = "x"
var data = X.global[type] ?? "Default value for missing keys"
}
If we look at the Dictionary implementation, subscript is returning a ValueType as optional because it doesn't know if the key is exists or not:
//Reading a key that is not present in `self` yields `nil`.
//Writing `nil` as the value for a given key erases that key from `self`.
subscript (key: KeyType) -> ValueType?
So when we try to get a value from our Dictionary we get it as an optional from the subscript; that is we have to unwrap the optional to get the underlying object. As mentioned in earlier answers, option2 is preferred.
guard var data = X.global[type] else {
//key = 'type' doesn't exists
}
//key exists so do something with 'data'

Cannot assign a value of type '[NSObject : AnyObject]' to a value of type '[String : AnyObject]!'

I am getting this error from the FireBase ios-swift-chat-example.
While assigning the dictionary to constant variable, you don't required to type cast because you are already creating dictionary of type [String : AnyObject] which required for assignment to the UITextView.linkTextAttributes.
let attributes = [NSForegroundColorAttributeName:cell.textView!.tintColor,NSUnderlineStyleAttributeName:1]
cell.textView!.textView.linkTextAttributes = attributes
Check whether you are dealing with string or dictionary. In my case i handled dictionary as string.