Convert Results<t> to [AnyObject] - ios

i'm using realm as a backend, however when i wanna show my realm in the following class i keep getting following error: Cannot convert value of type Results<League> to expected argument type [AnyObject]]?
do i need to map the result or what is my options?
let realm = try! Realm()
let predicate = NSPredicate(format: "#matches.#count > 0")
menuArray = realm.objects(League).sorted("id").filter(predicate)
let menuView = BTNavigationDropdownMenu(title: menuArray!.first!.name!, items: menuArray!)
self.navigationItem.titleView = menuView

I think there is a difference between a value of type Results<Object> (which is a custom Realm container type) and a value of type [AnyObject] (which is a Swift array of AnyObject objects), so you're probably right in thinking that you need to convert the result.
Try this:
let menuView = BTNavigationDropdownMenu(title: menuArray.first!.name!, items: menuArray.map { $0 })
This approach is probably OK in the context of a simple dropdown menu like the one you're using, but there may be a degradation in performance in other contexts.

Related

How to find value difference of two struct instances in Swift

I have two instances from the same struct in Swift. I need to find out key-values that have the same keys but different values.
For example:
struct StructDemo {
let shopId: Int
let template: String?
}
let a = StructDemo(shopId: 3, template: "a")
let a = StructDemo(shopId: 3, template: "different a")
// My expectation is to return the change pairs
let result = [template: "different a"]
My approach is as show below but comes errors.
static func difference(left: StructDemo, right: StructDemo) -> [String: Any]{
var result:[String: Any] = [:]
for leftItem in Mirror(reflecting: left).children {
guard let key = leftItem.label else { continue }
let value = leftItem.value
if value != right[key] { // This is the problem. Errror message: Protocol 'Any' as a type cannot conform to 'RawRepresentable'
result[key] = right[key]
}
}
}
Appreciate for any suggestion and solutions.
Thank you
The problem that you are seeing is that you referred to
right[key]
but right is a StructDemo and is not subscriptable. You can't look up fields given a runtime name. Well, you can with Mirror which you correctly used for left, but you did not mirror right.
Using Mirror will lead to other issues, as you will have expressions with static type Any where Equatable will be required in order to compare values.
IMHO, your best bet is to avoid a generic, reflective approach, and just embrace static typing and write a custom difference functions that iterates all the known fields of your type. Hard coding is not so bad here, if there is only one struct type that you are trying to diff.
If you have a handful of struct types each needing diffs then that might be a different story, but I don't know a good way to get around the need for Equatable. But if you have a ton of diffable types, maybe you want dictionaries to begin with?

Intricate access to dictionary key

From a server I receive a JSON string, then I try to convert it to an NSDictionary this way:
let JSON = try NSJSONSerialization.JSONObjectWithData(rToData!, options:[])
guard let JSONDictionary:NSDictionary = (JSON as! NSDictionary) else {
print("My grandma is way more NSDictionary than this")
return
}
Once converted, I try to get some data contained in the dictionary: in particular I need an array I can access this way:
let myArray = JSONDictionary["data1"][0]["data2"];
XCode really doesn't like this idea, it puts an arrow under the first bracket and says Value of optional type "AnyObject?" not unwrapped, did you mean to use "!" or "?" ?. I follow its suggestion and I insert a "!", converting my preceding code to this:
let myArray = JSONDictionary["data1"]![0]["data2"];
At this point, the following line (where I count the number of elements in data2) shows an error, stating AnyObject has no member count.
The only thing that seems to work fine is this solution but, apart from being ugly and unreadable, I really don't understand it:
let myArray = (JSONDictionary["data1"]?[0]["data2"])!;
Can you help me understand why this basic access to a key in a dictionary must be so intricate?
I must say I like Swift but I spend a lot of time dealing with optionals and bizarre XCode alerts.
There is no guarantee that your JSON dictionary will contain a value for the key data1 (OK, you know it will, but Swift doesn't) so JSONDictionary["data1"] returns an optional. You need to unwrap the optional with ? or !
Also, since you have an NSDictionary, not a Swift dictionary, Swift doesn't know the type of the values, so they are AnyObject. Now again, you know it is an array, but Swift doesn't so you get an error stating that AnyObject doesn't have a count method.
While it is more verbose, it is cleaer for both the compiler and anyone else looking at your code if you split the line into multiple lines. It also lets you downcast the various objects so that Swift knows what is going on and handle any malformed JSON;
if let array1 = JSONDictionary["data1"] as? NSArray {
if let dictionary1 = array1[0] as? NSDictionary {
if let data2Array = dictionary1["data2"] as? NSArray {
let count=data2Array.count
}
}
}
You could implement appropriate else statements to handle errors
Optionals are one of Swift's most powerful features. They help avoid a whole family of bugs associated with uninitialised variables and special sentinnel values for boundary conditions. It is important that you learn how they can help you and not just throw ? or ! at your code until it compiles.

Realm: rearranging list of objects

Please, tell me, how to rearrange items of Realm's list of objects by index? I.e. I'm looking something like
let movingElement = array[oldIndex]
array.removeAtIndex(oldIndex)
array.insert(movingElement, atIndex: newIndex)
if it was with a casual Swift array of something.
But for List in Realm I can not do the same thing:
let realm = try! Realm()
var all = try! Realm().objects(element)
realm.write {
all.removeAtIndex() // all of type
Another option is to
let realm = try! Realm()
let element = try! Realm().objects(Element)[oldIndex]
realm.write{
realm.delete(element)
realm.add(...) // How to set index to place new object at?
}
But how to insert element in proper place? May be there is a proper method how to move elements of realm of the same type (class) by index?
Thanks in advance!
You cannot do it with query results, as they are unordered (or in a specific order if you sort them). But if you put them into Realm List (which you can store as member in a Realm object), then you can use both move and swap methods to reorder elements.
Here is the API docs for the the List type: https://realm.io/docs/swift/latest/api/Classes/List.html

error: Generic parameter 'R.Generator.Element' cannot be bound to non-#objc protocol type 'AnyObject'

I am querying HealthKit and saving it to CoreData. I fetch the data in a separate class. In TableViewController I append the data to an array:
if NSUserDefaults.standardUserDefaults().boolForKey("weightSwitch") == true {
xAxisDatesArray.append(cdFetchWeight.queryCoreDataDate())
yAxisValuesArray.append(cdFetchWeight.queryCoreDataData())
and pass it at tableView.dequeueReusableCellWithIdentifier
myCell.xAxisDates = xAxisDatesArray[indexPath.row]
myCell.yAxisValues = yAxisValuesArray[indexPath.row]
In UITableViewCell I initialise the variables (yAxisValues, xAxisDates) and pass them into a charting library which takes the x and y values and plot a chart.
class TableViewCell: UITableViewCell, TKChartDelegate {
var xAxisDates = []
var yAxisValues = []
plot....
I need to get the min and max values of yAxisValues so that I can set the appropriate y-axis range to the data.
I have tried to get the min and max with the following code:
func rangeMinAndMax(){
let minYvalue = minElement(yAxisValues)
let maxYvalue = maxElement(yAxisValues)
}
But this generates the error: Generic parameter 'R.Generator.Element' cannot be bound to non-#objc protocol type 'AnyObject'
- Question: Why and how can I fix it?
Any help would be much appreciated !
The thing to do in a situation like this is to throw away all the misleading dross and boil it down to the simplest possible case:
let arr : [AnyObject] = [1,2,3]
let min = minElement(arr) // same error: "Generic parameter blah-de-blah..."
So, you see, minElement doesn't work on an array of AnyObject, and that's what the error is telling you. And the reason is obvious: an AnyObject is not a Comparable. There is no "minimum" for a bunch of AnyObject things; the entire concept of one AnyObject being "less than" another AnyObject is undefined. You need to cast your array down to an array of something that minElement can work on, namely a Comparable of some kind.
For example, in that code, I can fix the problem like this:
let arr : [AnyObject] = [1,2,3]
let min = minElement(arr as [Int])
That is the sort of thing you need to be doing. Of course, what you cast down to depends upon what these elements actually are. It looks to me as if will probably be Double and NSDate respectively, but that's just a guess; I don't know what's in your arrays. You do (presumably). Note that an NSDate is not a Comparable so you will have a bit more work to do with that one.

Unable to use AnyObject in Swift

I don't understand an inch of how the AnyObject type in Swift is supposed to work. I am loading a Plist file into a NSDictionary instance in my Swift code (not shown here). Later I try to use some of the values from the Plist file in a UIPickerView:
// Trying to extract the first fruit
let fruitKeys = fruits.allKeys
let fruitKey = fruitKeys[0]
// This is another NSDictionary
let fruit = fruits.objectForKey(fruitKey)
// Getting a property of a fruit
let nutritions = fruit.objectForKey("nutritions")
let nutritionKeys = nutritions.allKeys
However I am not able to get the keys of a fruit by calling nutritions.allKeys. I get Could not find member allKeys. However, which part of the documentation have I misunderstood? I read that you can call any objective c method on an instance of AnyObject. Why do I need to cast or to some other magic here?
Should I cast everything to their real types? Or should I use AnyObject??
In short, yes you would generally want to cast to your defined type, here's how I would write it:
let fruitKeys = fruits.allKeys as [String]
let fruitKey = fruitKeys[0]
let fruit = fruits[fruitKey] as NSDictionary
let nutritions = fruit["nutritions"] as NSDictionary
let nutritionKeys = nutritions.allKeys
As I already mentioned in my comment, a possible change to your code would be:
let fruitKeys = fruits.allKeys
let fruitKey = fruitKeys[0]
let fruit = fruits.objectForKey(fruitKey)
let nutritions = fruit.objectForKey("nutritions")
let nutritionKeys : AnyObject? = nutritions.allKeys
I omitted downcasting every value because I saw it as pointless, so you might encounter some warnings, but it will work.

Resources