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

- (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.

Related

Adding value to NSObject key- Expression is not assignable

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

How to simplify Swift array initialization

This is in reference to https://stackoverflow.com/a/47765972/8833459.
The following statement is given:
let fooPaths: [WritableKeyPathApplicator<Foo>] = [WritableKeyPathApplicator(\Foo.bar), WritableKeyPathApplicator(\Foo.baz)]
Is there an init or something else that can be done so that the following (or something similar) might also work?
let fooPaths: [WritableKeyPathApplicator<Foo>] = [\Foo.bar, \Foo.baz]
The original statement is just too much typing! My "preferred" method currently gives the error:
error: cannot convert value of type 'WritableKeyPath<Foo, String>' to expected element type 'WritableKeyPathApplicator<Foo>'
The type is unnecessary:
let fooPaths = [WritableKeyPathApplicator(\Foo.bar), WritableKeyPathApplicator(\Foo.baz)]
The second Foo is unnecessary.
let fooPaths = [WritableKeyPathApplicator(\Foo.bar), WritableKeyPathApplicator(\.baz)]
Also the first one if you do provide the type:
let fooPaths: [WritableKeyPathApplicator<Foo>] = [WritableKeyPathApplicator(\.bar),
WritableKeyPathApplicator(\.baz)]
If the major concern is typing, add a local typealias:
typealias WKPA<T> = WritableKeyPathApplicator<T>
let fooPaths: [WKPA<Foo>] = [WKPA(\.bar),
WKPA(\.baz)]

Why accessing this json sub elements by index raises this error?

this is the part of the json
"feature_id" = (
3047,
3084,
3095,
3100,
3121,
3124,
3182,
3272,
3273,
3274
);
this is how I access json, I use Alamofire.
var features_id = self.jsonD["results"]!["place_basic_info"]!!["feature_id"]!!
now the problem is in here
features_id[0] as? String
the error raised is :
ambiguous use of 'subscript'
the weird thing is this shows up when I try to build for the device, but not when running, how to solve this problem ? and why it shows up?
ambiguous use of 'subscript'
The issue is that the compiler doesn't know that features_id is an array, so it is unable to subscript it by index.
You have to give the object's type to the compiler, for example with optional binding and casting:
if let featID = features_id as? [Int] {
// here featID is features_id unwrapped as an array of Ints
}

Cryptic F# error - The signature and implementation are not compatible because the declaration of the type parameter requires a constraint of 'T=null

I have a small piece of F# code that is generating a cryptic error I can't figure out....
namespace epic.View
open System
open FSharp.Desktop.UI
[<AbstractClass>]
type public FieldModelBase<'ValueType>() =
inherit Model()
let mutable fieldCaption: string = null
let mutable fieldValue: 'ValueType = null
[<DerivedProperty>]
member this.Caption with public get() = sprintf "%s" fieldCaption and set value = fieldCaption <- sprintf "%s" value; this.NotifyPropertyChanged "Caption"
[<DerivedProperty>]
member inline this.Value with public get() = fieldValue and set value = fieldValue <- value; this.NotifyPropertyChanged "Value"
which generates the following error:
The signature and implementation are not compatible because the
declaration of the type parameter 'ValueType' requires a constraint of
the form 'ValueType : null
What does this mean and how do I resolve it? It looks like I should be adding a type constraint on the 'ValueType type-parameter to require it is... mutable? is that right?

How to iterate over a list of type Class to edit the properties of its objects in Groovy

I know there are more elaborate ways to achieve this in Java, but Groovy should have a concise way to do the same as per http://groovy.codehaus.org/Looping
Class Currency.groovy
class Currency {
String name
double rate
}
CurrencyController
def select(){
List<Currency> selectedCurrencies = Currency.getAll(params.currencies)
selectedCurrencies.eachWithIndex { obj, i -> obj.rate = update(obj.name)};
[selectedCurrencies:selectedCurrencies]
}
def update(String sym){
return sym
}
The above code throws:
No signature of method: currencychecker.CurrencyController$_$tt__select_closure12.doCall() is applicable for argument types: (currencychecker.Currency)
Thanks to #dmahapatro, the issue was that I was using an iterator variable obj[i], even though obj itself is the iterated object. The rest is correct!
I experimented with selectCurrencies.each as well instead of selectCurrencies.eachWithIndex however the right one in this case is eachWithIndex

Resources