What means __NSSingleObjectArrayI in Objective C? when I try to read a Json - objective-c

I have this code Json format:
{
"weather": [{
"description": "clear sky",
"icon": "01n"
}],
"base": "stations",
"main": {
"temp": 285.514
},
"clouds": {
"all": 0
},
"dt": 1485792967,
"id": 1907296
}
And I want to retrive icon string (01n)
And use this code:
#property(nonatomic,strong) NSString *cityImageName;
self.cityImageName = [[dataJson valueForKey:#"weather"] valueForKey:#"icon"];
And later when I check the variable print:
<__NSSingleObjectArrayI 0x604000009890>(
01n
)
Finally how can I get the string directly? not like a __NSSingleObjectArrayI

You got caught in the Key-Value Coding Trap.
valueForKey has a special behavior. Applied to an array it returns always an array of all values for the given key.
Never use valueForKey unless you intend to use KVC. The recommended syntax is objectForKey or – preferable – key subscription and in case of the array index subscription.
In this case you want to get the value for key icon of the first item in the array for key weather.
self.cityImageName = dataJson[#"weather"][0][#"icon"];
However I would add a check if the array is not empty to avoid an out-of-range exception
NSArray *weather = dataJson[#"weather"];
if (weather && weather.count > 0) {
self.cityImageName = weather[0][#"icon"];
}

__NSSingleObjectArrayI is one of the implementations of the NSArray class cluster. It's not really important to this question other than knowing that it's an array.
The reason you're getting an array (of one element) instead of a string is because the JSON you're working with contains an array with one dictionary inside of it:
"weather": [{
"description": "clear sky",
"icon": "01n"
}],
Note: the square brackets surrounding the curly brackets.
So, when you call [dataJson valueForKey:#"weather"] you get back the object that represent this part of the JSON:
[ { "description": "clear sky", "icon": "01n" } ]
Which is in this case has been decoded as an NSArray containing one NSDictionary with two keys.
When you then call valueForKey: on that array it
Returns an array containing the results of invoking valueForKey: using key on each of the array's objects.
In other words, because [dataJson valueForKey:#"weather"] is an array of one dictionary, [[dataJson valueForKey:#"weather"] valueForKey:#"icon"] is an array of only the value for the "icon" key in that dictionary.
If the JSON you're working with always has this format, then you can get the firstObject from the array to get a hold of the first string (or nil if the array was empty).

Related

Kafka Lenses SQL - How to WHERE filter based on objects nested in an array

I am working in Kafka Lenses v2.2.2. I need to filter based on a the value of an object inside an array.
Sample message (redacted for simplicity):
{
"payload": {
"Data": {
"something" : "stuff"
},
"foo": {
"bar": [
{
"id": "8177BE12-F69B-4A51-B12E-976D2AE37487",
"info": "more_data"
},
{
"id": "06A846C5-2138-4107-A5B0-A2FC21B9F32D",
"info": "more_data"
}
]
}
}
In lenses this actually appears as a nested object with a integer properties... 0, 1, etc.
So I've tried this, but it is throwing an error: .0 appears out of place
SELECT *
FROM topic_name
WHERE payload.foo.bar.0.id = "8177BE12-F69B-4A51-B12E-976D2AE37487"
LIMIT 10
I tried wrapping the 0 in double/single quotes as well and that throws a 500 error.
I copied and pasted the UUID from the first message in the topic, so it's definitely there. I also copy and pasted the labels to rule out typos. I am thinking there is some special way to access arrays with nested objects like this, but I'm struggling to find any documentation or videos discussing it.
I can be confident the value is stored in the first array element, but methods that can search all objects would be awesome as well.
The syntax (if you know the array index - as in my initial question) is:
SELECT *
FROM topic_name
WHERE payload.foo.bar[0].id = "8177BE12-F69B-4A51-B12E-976D2AE37487"
LIMIT 10
Though I am still struggling to do this if the array index is unknown and you need to check them all. I'm assuming at this point it's not possible without a series of OR statements in the WHERE clause that checks them all.

JsonSchema - Defining a white-listed set of values

I feel like there's no chance my question was not asked before, but I couldn't find an answer anywhere.
As the title suggests, I'm trying to create a JSON schema that will validate an array if, and only if, All of the values in it are defined in a pre-defined set.
For example:
If the predefined set contains {"One", "Two", "Three"}, and the array I'm trying to validate is ["One", "Two"], then the array should be valid.
But if the array is ["One", "Two", "Four"], then the array would be invalid.
So I know of enum but it doesn't accomplish my goal since it validates as long as ONE of the values is defined in the predefined set.
I also know of min/max-contain combinations, tho they may interfere with the requirement that none of the values in the predefined set MUST appear. They all may, or may not appear.
Does anyone have an idea how to accomplish such requirements?
Okay, let's break that down:
You want to validate each item of an array against a schema. That's the items keyword: https://json-schema.org/understanding-json-schema/reference/array.html#items
each item of the array should have a value that exists in a predefined set. That's the enum keyword: https://json-schema.org/understanding-json-schema/reference/generic.html#id4
Putting it together:
{
"type": "array",
"items": {
"enum": [ "one", "two", "three" ]
}
}

Why does Mule DataWeave array map strip top level objects?

I'm trying to understand the behaviour of DataWeave v1.0 when it comes to mapping objects in a root JSON array.
At this stage I just want to map each item in the array as-is without mapping each individual field of the item. I need to do it for each item in the array because later on I want to edit some of the fields, but since there are potentially many I don't want the overhead of mapping them one-by-one.
This is my dataweave:
%dw 1.0
%output application/json
---
payload map {
($)
}
This is my input:
[
{
"MyString": "ABCD",
"MyNumber": 123,
"AnObject": {
"MyBool": false,
"MyNestedObject": {
"MyNestedString": "DEF"
}
}
}
]
I want my output to be (at this stage) exactly the same as my input.
Instead my (wrong) output is:
[
{
"MyString": "ABCD",
"MyNumber": 123,
"MyBool": false,
"MyNestedObject": {
"MyNestedString": "DEF"
}
}
]
As you can see the object AnObject is missing, although its children remain.
Things are worse if the input includes arrays, for example the input:
[
{
"MyString": "ABCD",
"MyNumber": 123,
"AnObject": {
"MyBool": false,
"MyNestedObject": {
"MyNestedString": "DEF"
}
},
"AnArray": [
{
"Title": "An array item",
"Description": "Pretty standard"
}
]
}
]
Throws the error:
Cannot coerce a :array to a :object.
I have played around with the mapObject operation on the root array items too, but I always run into the same behaviour. Is anyone able to explain what is happening here, and show me how I can copy each item in the root payload across dynamically.
Mule runtime is 3.9.1.
To go through each item in the array and let them as it is, you should do payload map $, that is the same as payload map ((item) -> item)
What you were doing is the same as: payload map ((item) -> {(item)}).
Here what you are returning for each item is the expression {(expr)} that in the DW version that runs on Mule 3.9.1, it has an accidental behavior where the expression tries to coerce expr (that in this case is an object) to array of objects and then it will try to flatten all the objects in that coerced array inside the parent object. It looks like is trying to coerce the value of the keys too, that's why DW throws the error.
This behavior of {()} changes in newer versions of DW.

RestKit resolve objects given an id or partial representation in JSON

I have a JSON array, something like:
[{
"name": "John Smith",
"occupationId": 3
},
{
"name": "Steven Davis",
"occupationId": 2
}
]
The occupation response looks something like:
[{
"id": 2,
"name": "Teacher"
},
{
"id": 3,
"name": "Teaching Assistant"
}
]
Is there a way to allow RestKit to request the correct data for the occupations, given only their id? I know this can be done if the data is persisted using CoreData, via the addConnectionForRelationship:connectedBy: method, but I would rather that the data is transient, given that the server is local and there really is no need to persist the data. I'm also aware that RKObjectMapping does not support the identifiactionAttributes property, meaning I cannot (to my knowledge) designate a way to allow the class to declare a unique, identifying property.
Any help would be appreciated. I am using a mix of Objective-C and Swift, and as such, I do not mind answers in either language.

RestKit: Map single object into existing array

I have the following JSON structure which i get from a RestService:
{
"customer": {
"id": "123456",
[more attributes ....]
"items": [
{
"id": "1234",
},
{
"id": "2345",
}
[more items...]
]
}
}
which i successfully map into Core Data using RestKit. From another RestService (which i can not change) i then get more details to one single item in the items array. the JSON answer looks like
{
"customer": {
"id: "123456",
"item": {
"id": "1234",
"name": "foo",
[other attributes...]
}
}
}
Now the question: How can i map the second answer, so that the single item is added to the items array (or updated if it is already in there)?
Thanks for any ideas!
If you already know how to map JSON to Core Data, all that's left is just fetch theobject you want to add your item attributes to(using id or something else) and then just set it,rewriting the old one,or adding new fields.That's just general approach
If you set the appropriate primaryKeyAttribute of the RKManagedObjectMapping object you should be able to perform the mapping as you want it to.
It would actually be easier to help you, if you would post some of your mapping code, but this is how I meant it to be
Create the mapping for your customer object, defining all possible attributes and declare the mappingObject.primaryKeyAttribute = #"id"
Execute the mapping with the first request (or first answer as you put it)
After the first mapping step is finished execute the second request
This should initially create the customer objects you want and then update them.