Adding value to NSObject key- Expression is not assignable - arrays

I’m trying to add a value I get back from an API call to an object in Objective-C. I get an error in Xcode saying “Expression is not assignable” and don’t understand why. In my carObj I have an object called warrantyPlan with a nil value and I’m trying to set the value for warrantyPlan. What am I doing wrong in this method?
NSArray *carUUIDs = [carData valueForKeyPath:#"uuid"];
NSString *ownerUUID = ownerRecord[#"uuid"];
if (ownerID) {
NSManagedObjectContext *context = [DataCenter viewContext];
NSObject *carObj = [context objectsForEntityName:[CarObject entityName] matchingUUIDs:carUUIDs];
for (id carID in carUUIDs){
[WarrantyPlansService getWarrantyPlansForCarWithCarID:carID ownerID:ownerUUID completion:^(NSArray* response, NSError* error){
//attach the response to the carData
NSLog(#"%#", [carObj valueForKeyPath:#"warrantyPlans"]);
[carObj valueForKeyPath:#"warrantyPlans"] = response;
}];
}

[carObj valueForKeyPath:#"warrantyPlans"] is an expression that has a value like literally 42 is an expression that has a value. It's not an expression like foo that is a variable that has a value of 42 and can be changed by using it on the left hand side of an equals sign.
To change it you want:
[carObj setValue:response forKeyPath:#"warrantyPlans"]
These two are called the generic getter valueForKey: and the generic setter setValue:forKey: in the KeyValueCoding guide: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/index.html

Related

Regex to match the last value in given data

I get data from a URL, and am working on the data to check for a few conditions. The data from the URL look like this:
1528190345":100,"1528190346":100,"1528190368":100,"1528190414":100,"1528190439":99,"1528190440":99,"1528190463":100,"1528190485":100,"1528190508":100,"1528190550":100,"1528190575":100,"1528190576":100,"1528190599":100,"1528190600":100,"1528190622":100,"1528190667":100,"1528190688":100,"1528190689":100,"1528190712":100,"1528190736":100,"1528190762":100,"1528190785":100,"1528190786":100,"1528190807":100,"1528190828":100,"1528190853":100,"1528190877":100,"1528190901":100,"1528190925":100,"1528190948":100,"1528190968":100,"1528190991":100}}]
====
I have converted that too JSON
{"metric"=>"Insta_real-unique_value", "tags"=>{"host"=>"letme.quickly.com", "tier"=>"2", "device"=>"tester1", "dc"=>"xxx"}, "aggregateTags"=>["device_name", "device_ip"], "dps"=>{"1526972408"=>100, "1526972424"=>100, "1526972440"=>100, "1526972456"=>100, "1526972472"=>100, "1526972488"=>100, "1526972504"=>100, "1526972520"=>100, "1526972536"=>100, "1526972552"=>100, "1526972568"=>100, "1526972569"=>100, "1526972584"=>100, "1526972585"=>100, "1526972601"=>100, "1526972617"=>100, "1526972633"=>100, "1526972649"=>100, "1526972665"=>100, "1526972681"=>100}}
I want to extract the value that corresponds to 100. When I do this:
url = "#{URL}"
uri = URI(url)
response = Net::HTTP.get(uri)
value = response[-6..-4]
puts value
I get the last value, but when the last value changes to 99/9/0, it prints :99 or ":9.
Is there a way to get the exact value as is?
When dealing with JSON data, it's almost always better to parse the data properly rather than using regex against the string.
In this case, we can do:
JSON.parse(response)['dps'].values.last #=> 100
If the response is a json response, you must use a json parser else if is not a json response, you can use a regex expression with a Regex Object.
In case of a json response, assuming that the object is something like is declared into the variable response of the next code, you can parse it into a JObject. (using Newtonsoft.Json available from nuget repository).
See the next example :
string response = "[{\"response\":{\"1528190345\":100,\"1528190346\":100,\"1528190368\":100,\"1528190414\":100,\"1528190439\":99,\"1528190440\":99,\"1528190463\":100,\"1528190485\":100,\"1528190508\":100,\"1528190550\":100,\"1528190575\":100,\"1528190576\":100,\"1528190599\":100,\"1528190600\":100,\"1528190622\":100,\"1528190667\":100,\"1528190688\":100,\"1528190689\":100,\"1528190712\":100,\"1528190736\":100,\"1528190762\":100,\"1528190785\":100,\"1528190786\":100,\"1528190807\":100,\"1528190828\":100,\"1528190853\":100,\"1528190877\":100,\"1528190901\":100,\"1528190925\":100,\"1528190948\":100,\"1528190968\":100,\"1528190991\":100}}]";
List<Dictionary<string, Dictionary<string, int>>> values = JsonConvert.DeserializeObject<List<Dictionary<string, Dictionary<string, int>>>>(response);
Dictionary<string, Dictionary<string, int>> firstLevel = values[0]; // Access to the first object of the list closed with ']'
Dictionary<string, int> secondLevel = firstLevel["response"]; // Access to the first object response and get's it's object context of first '}' starting from the end of response
/** This is an option, if you ever knows the name of the element (1528190991) */
int thirdLevel = secondLevel["1528190991"]; // Access to the last element of the object by it's name, context of second '}' starting from the end of response.
Console.WriteLine(thirdLevel);
/** This is another option if you doesn't know the name of the element and wants ever the last element. */
List<int> listOfValues = secondLevel.Values.ToList();
Console.WriteLine(listOfValues[listOfValues.Count-1]);
Note that i've chenged a little bit your response adding [{\"response\":{\" at the start to become a json response.
If is not a json response you can use this pattern with regular expression :
:(.{2,6})}}\]$
Hope will help!

Clang won't complain about [id respondsToSelector:#selector(foo)];

- (void)foo {
id objc = nil;
[objc respondsToSelector:#selector(foo)]; // Works fine
}
And
#protocol DummyProtocol
#end
//...
- (void)foo {
id<DummyProtocol> objc = nil;
[objc respondsToSelector:#selector(foo)]; //Error: No known instance method for selector 'respondsToSelector'
}
I know in this case DummyProtocol doesn't inherit from NSObject, therefor the error occurs. But the first case is kind of tricky, id is essentially a C struct pointer which point to a objc_object struct. It shouldn't suppose to have any ObjC method implementation...
And the dot syntax will generate error in both cases, like
- (void)foo {
id obj = nil;
obj.description; //Error: Property 'description' not found on object of type '__strong id
id<DummyProtocol> objc = nil;
objc.description; //Error: Property 'description' not found on object of type '__strong id<DummyProtocol>'
}
I've check the Clang documentations with not luck. This has been in my head for about 2days, any suggestions will help...
id with [] syntax will accept any selector from any class/protocol of your project at compilation
id<DummyProtocol> will only accept selectors from DummyProtocol
. syntax will only accept selectors from a specific concrete class/protocol (so it will never work with id alone)
Note that description isn't part of your DummyProtocol.

Swift: Changing value of global variable via function.

I'm trying to change the value of a global variable transferredData in the function didTransferData(_ data: Data?). My code looks like this:
var transferredData: [Double] = [0.0]
func didTransferData(_ data: Data?) {
var dataArray = [CUnsignedChar](repeating:0, count: (data?.count)!)
data?.copyBytes(to: &dataArray, count: dataArray.count)
let dataInt = dataArray.filter({ Int(String($0)) != nil }).map({ Int(String($0))! })
let dataDouble = dataInt.map { Double($0) }
print("Data double: \(dataDouble)")
transferredData = dataDouble
}
Printing transferredData inside of didTransferData returns the correct array, containing all values of dataDouble. But when I try to access it in this function later on
func returnData() -> [Double]{
print("return Data: \(transferredData)")
return transferredData
}
it returns [0.0]. I'm not sure if I'm missing something crucial here, but I thought that even if I change the value of a global variable in a function, the new value should be accessible for every other functions, too.
Thanks for any advice!!
You said that this code is inside a class. The variable transferredData is not a global, it is a member variable.
There is one of these per object of the class. I suspect that you are not using the same object to make these two calls.
You could make the member shared between all objects by declaring it static, but I think it would be better to leave as is and arrange to use the same object.
EDIT: based on comment
If you write the code
let centralInstance = CentralViewController()
You will get a new object with its own transferredData member initially set to [0.0]. You need to either
Get a reference to the same VC object that has the data
Store the data some where else in an object that you can get back (since the VC might be gone)
To hack something that works (not recommended, but to help understand)
You could move transferredData out of the class and make it an actual global variable. I would do this only to help you get past this issue and understand what's going on.
You could also make it static, which makes all of the VC's share the same instance of the transferredData
When you understand what is going on, you can try to do something a little better (at least move it to its own model object, and not in the VC at all). The next simplest thing is some kind of singleton to manage it -- this is just a glorified global variable but puts you more on the road to a more typical solution.
Where is the problem:
$ swift
Welcome to Apple Swift version 3.0.2 (swiftlang-800.0.63 clang-800.0.42.1). Type :help for assistance.
1> var data:[Double] = [0.0]
2.
3. class MuckWithData {
4.
5. func showData () -> [Double] {
6. print ("Data: \(data)")
7. return data
8. }
9.
10. func modifyData () {
11. data = [1.0]
12. }
13. }
data: [Double] = 1 value {
[0] = 0
}
14>
15> var mucked = MuckWithData()
mucked: MuckWithData = {}
16> mucked.showData()
Data: [0.0]
$R0: [Double] = 1 value {
[0] = 0
}
17> mucked.modifyData()
18> mucked.showData()
Data: [1.0]
$R1: [Double] = 1 value {
[0] = 1
}
Probably your computation for dataDouble is actually [0.0] and thus it appears that transferredData didn't change, but it did.

How to add to an array of objects, an object that is inherited? (Swift, XCode)

var allCards = [CCard]
var cardsMade = 0
^^ is outside of my view controller class as to make it global and accessible in all other view controller files.
in another view controller i have
#IBAction func saveInfo(sender: UIButton) {
let a = CCreature(n: cName!, e: cExpansion, ec: cEnergy!, tc: cTurnCount!,
ef: cEffect!, at: cStrength!, ht:cHealth!, sp: cSpeed!, sb: false)
allCards.append(a)
cardsMade++}
so when the saveInfo button is pressed, i put all the information the user has typed (which were in UITextFields, and then saved into the corresponding vairables cEnergy etc..) into a subclass of CCard called CCreature, with all of the information. After I create the instance of the class, i am trying to store in the array allCards. I am getting an error on the line:
var allCards = [CCard]
Expected member name or constructor call after type name
And in the line where a is appended to the array i am getting this error:
Cannot convert value of type 'CCreature' to expected argument type 'inout Array < CCard >'
I was also getting this error message before, when my program was compiling:
fatal error: Array index out of range
Any ideas?
As you have it [CCard] is a type declaration, you could use it as:
var allCards : [CCard]
but, that won't actually initialize allCards to be useful, alternatively, you could actually create the array and initialize it using:
var allCards = [CCard]()
Where you're using the default array constructor
It's not the entirety of your example, because you didn't include a lot of the pieces, but stripped down to show usage, would be:
var allCards = [CCard]()
func saveInfo() {
let a = CCreature()
allCards.append(a)
}

swift setting string from array element error

So im grabbing a property from core data, using a dictionary. And it grabs it just fine. However, when I try to take that single returned attribute and assign it to the navigationitem.title it throws some nasty error. Am I missing something here..
Its not actually outputting an error message in the console but instead is giving me this:
Thread 1: EXC_BREAKPOINT(code+exc_I386_BPT.....
on this line.
0x10707a5f3: nopw %cs:(%rax,%rax)
Also its saying
0 swift_dynamicCastObjCClassUnconditional
code:
override func viewDidLoad() {
super.viewDidLoad()
let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let context:NSManagedObjectContext = appDel.managedObjectContext
let frequest = NSFetchRequest(entityName: "Round")
frequest.propertiesToFetch = NSArray(object: "course")
frequest.returnsObjectsAsFaults = false
frequest.returnsDistinctResults = true
frequest.resultType = NSFetchRequestResultType.DictionaryResultType
var fetchedArray = context.executeFetchRequest(frequest, error: nil)
//this is the line that throw the error...why won't it let me set the title to the array of the single returned result?
self.navigationItem.title = fetchedArray[0]
println(fetchedArray)
}
Without a specific error message you are receiving, this is just a guess...
NSArray un untyped contents (that is to say that elements are of type AnyObject), so the compiler probably doesn't think you can set AyObject as a string. So likely need something like:
self.navigationItem.title = fetchedArray[0] as String
Or:
self.navigationItem.title = String(fetchedArray[0])
To start, I would check couple of things to see if the problem is in the fetched array or in the navigation item:
what exactly is returned in fetchedArray[0]? Is is a string? A nil? Something else? Does it actually have anything at index 0? After checking if fetchedArray is not nil and has any elements, you could use "\(fetchedArray[0])"
What is the state of navigationItem? Is it actually instantiated at the time you are trying to set it's title property? I would suggest checking it for nil. You can also try assigning it a string like this: self.navigationItem.title = "Hello" and see if it fails.

Resources