KVC valueForKey return a __NSCFConstantString instead a __NSCFString - kvc

I use KVC in my projects.
And, in one of my classes, I wrote the property :
#property ( nonatomic, strong ) NSString *notes;
I want to put a NSString object in that property :
And before setting the value, I want to test the class name of the destination.
a = [ newContainer valueForKey:#"notes"];
if( a != nil && ![ b isKindOfClass:[ a class ] ] )
// here b is the new NSString value
The result is that xcode indicates that the classes aren't the same !
(gdb) po [ b class ]
__NSCFString
(gdb) po [ a class ]
__NSCFConstantString
I read that is not very important and that __NSCFConstantString is a private subclass of NSString.
But, in my case, I need to check all properties of my object before updating it.
And I don't want to had in my code :
// OK, classes aren't the same ...
// ---- BUT WE MUST test it again to know if a is a NSString and b a subclass of NSString or anything else ...
beurk !
Is anyone have the same problem ?
Thanks a lot for your help !

Three points:
1- You should check against [NSString class], the publicly exposed class of your property, not against the class of the current value of your property.
Imagine what happens when you check against the value class, instead of the property class: after setting your property to a NSMutableString, which is a perfect instance of NSString, you could not any longer set it to a regular NSString (since NSString is not a subclass of NSMutableString). Your current problem is a variant of the one described in this paragraph, which may be easier to understand.
2- The test should be done in the class that owns the property, not outside as you are doing now. Because only that class is entitled to know about the type of object it accepts.
3- So. Use the standard validateValue:forKey:error: method, which is your friend here. This method would be implemented by the class, and it would make sure notes is a NSString. Outside of the class, you would not check the type of the value directly, but ask the container class to validate it.
And voilà !

Related

Realm and indexes on properties

CONTEXT
Realm does not support indices on relationship properties (objects). https://realm.io/docs/objc/latest/#indexed-properties
If you try, it'll throw an error.
We have a situation, where we need to query a model's relationship and another property.
Typically you would do this by having a covering index across (foreign_id, property), but this does not appear to be possible in Realm (yet?)
For example
#interface Book : RLMObject
#property NSNumber<RLMInt> * page;
#end
#interface Page : RLMObject
#property Book * book;
#property NSNumber<RLMInt> * line;
#end
[Page objectsInRealm:realm where:#"book.uuid = %# AND page.line = %#", uuid, #1];
QUESTION
What is the best way to set up indices so that the query above is optimal?
Are relationships already indexed?
Or Do I create another property on Page, called book_uuid, and index on that?
Cheers
Realm doesn't really cater to the foreign key mechanism of relational databases, so it's easier to get out of that mindset when designing your data model.
In this case, I think it would be more appropriate that your Book model stores an array of all of your pages (sort of an inverse to the foreign key concept), which you can use to initially filter the pages to just that book, and to then query for the specific page line:
#interface Page : RLMObject
#property NSInteger line;
#end
RLM_ARRAY_TYPE(Page)
#interface Book : RLMObject
#property RLMArray<Page *><Page> *pages;
#end
Book *book = [[Book allObjects] firstObject];
Page *page = [[book.pages objectsWhere:#"line = %#", #1] firstObject];
As long as you've marked line as an indexed property, this should work very quickly in theory. But since you've mentioned you've got thousands of page lines, I'd be curious to see what the real-world performance of this would be.

Determining super class for registered user types

I am attempting to determine which classes are subclassed from several different types. For example, if E1 extends A, E2 extends A, and E3 extends B, I want to find all classes that are subclassed from A and return a list of the types E1 and E2. These types are registered with the QMetaSystem.
My first attempt was to iterate over the user declared types, instantiate it, and get the superClass name:
int type = QMetaType::User;
while( QMetaType::isRegistered(type) ) {
QObject *o = (QObject*)QMetaType::construct(type);
QString parent = o->metaObject()->superClass()->className();
}
This seemed like a bad idea when I wrote it and didn't expect it to work. Unsurprisingly, it segfaults when attempting to get the metaObject.
Is it possible to get the information I need from the QMetaType or is there another way of getting this information?
Update
The problem seems to be in trying to iterate over all the user types. Before I register my types, some Qt type seem to be getting registered before mine. Specifically, the two registered types are QPaintBufferCacheEntry (typeId = 256) and QPaintBufferCacheEntryV2 (typeId = 257). I can initialize the object just fine, but it crashes when I attempt to get the meta object, so I'm thinking the cast is illegal. I'm not quite sure where these are being registered because my code base is not doing it explicitly.
I took this to mean that it just wasn't safe to iterate over and construct each of the user types.
Your idea is correct. This should give you the name of the parent class:
QObject *o = (QObject*)QMetaType::construct(type);
QString parent = o->metaObject()->superClass()->className();
For it to work, your classes must have been declared with Q_DECLARE_METATYPE(Type) and registered with qRegisterMetaType(). This is the case as QMetaType::isRegistered(type) is true.
Your user defined classes must also inherits from QObject (directly or not) and have the Q_OBJECT macro in their definition. This could explain your segfault.
superClass() can also return 0 if there is no parent class, but here all your classes should at least inherit QObject.
There is also QObject::inherits(const char * className) to know if an object is of a class inheriting, even indirectly, from className.

Subclassing NSString

Using WSDL2ObjC I am getting lot of classes which are subclasses of NSString.
I am finding it troublesome to initialize the NSString value of any object of those classes.
Say my class looks like this :
#interface mClass ; NSString {
int value;
}
Now in my code I would like to use objects of mClass as both NSString and also want to use its attribute value which is an integer.
How can I do that?
I am trying to use code like this
mClass *obj = [[mClass alloc] initWithString:#"Hello"];
But it's showing me an error saying I am using an abstract object of a class , I should use concrete instance instead.
If you really need make NSString subclass you should override 3 methods:
- (instancetype)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer;
- (NSUInteger)length;
- (unichar)characterAtIndex:(NSUInteger)index;
For example:
MyString.h
#interface MyString : NSString
#property (nonatomic, strong) id myProperty;
#end
MyString.m
#interface MyString ()
#property (nonatomic, strong) NSString *stringHolder;
#end
#implemenation MyString
- (instancetype)initWithCharactersNoCopy:(unichar *)characters length:(NSUInteger)length freeWhenDone:(BOOL)freeBuffer {
self = [super init];
if (self) {
self.stringHolder = [[NSString alloc] initWithCharactersNoCopy:characters length:length freeWhenDone:freeBuffer];
}
return self;
}
- (NSUInteger)length {
return self.stringHolder.length;
}
- (unichar)characterAtIndex:(NSUInteger)index {
return [self.stringHolder characterAtIndex:index];
}
#end
It might be smarter to use a wrapper class that internally uses NSStrings to do whatever operations or manipulations you are trying to do. However this will cause you to need to overload any functionality of NSString you want (such as getting the length of the string).
Or, you could create a category of NSString (found right next to Objective-C class in the new file window). This allows you to add any properties or methods that you wish to be "added" to the NSString class. Now just import this category wherever you wish to use it and you will have all of your custom functions available on any NSStrings objects.
Do you really need to subclass NSString? It’s a class cluster, which (apart from other things) means it’s hard to subclass. There’s a good post by Mike Ash on subclassing class clusters. If you didn’t know that class clusters existed you are probably new to Cocoa and in that case the best short answer is don’t try to subclass class clusters.
There’s also previous questions about subclassing NSString here on Stack Overflow. Next time you might want to search a bit before asking a new question.

How to access to Object property When the propety I want to access to it's in a String variable

It's too complicate to explain but I'll give you an example
I have an AS3 ResultEvent Object
and this object has several propeties which can be accessed by this like:
event.result.name or event.result.age .....
and, I have this String variable: eventProperty:String that contains "name" or "age"
How do I access to event.result. with the variable?
thank you.
The ActionScript (or ECMAScript) . operator is just syntactic sugar, useful but not really needed. For what you want to do you can use the normal object property access operator [].
So you have to do it like this event.result[ eventProperty ].
Good luck,
Alin
You should probably move your ResultEvent object into an actual Object type first. Then you can access the properties via the object. If your object is an arraycollection, make sure to immediately pass the ResultEvent into an arraycollection since you cannot cast it as you normally might (ArrayCollection)ResultEvent. Here is how to throw the result into an object:
var yourObjectName:Object = event.result;
and here is how to throw it into an arraycollection if you need to:
var yourArrayCollection:ArrayCollection = event.result as ArrayCollection;

What does this this ActionScript syntax mean? ( Syntax for returning Objects Inline )

I am a Java programmer and need to work on a Flex/ActionScript project right now. I got an example of using ITreeDataDesriptor from Flex 3 Cookbook, but there is one line of actionscript code that's hard for me to understand. I appreciate if someone could explain this a little further.
public function getData(node:Object, model:Object=null):Object
{
if (node is Office) {
return {children:{label:node.name, label:node.address}};
}
}
The part that I didn't understand was "{children:{label:node.name, label:node.address}}". Office is simply a value object that contains two String properties: name and address.
The following return expression (modified from the question) ...
return {children:{label:node.name, body:node.address}}
... is functionally equivalent to this code ...
var obj:Object = new Object();
obj.children = new Object();
obj.children.label = node.name;
obj.children.body = node.address;
return obj;
The anonymous object returned in the question code complicates matters because it defines a property twice. In that case, the first declaration is used, and the subsequent one(s) are ignored. No compile-time or runtime error is thrown.
I think in Java you would call that a map or an associative array. In Javascript and Actionscript you can say this to create an object with certain properties:
var myobject = {
'prop1': 100,
'prop2': {
'a': 1
}
}
trace( myobject.prop1 ); // 100
trace( myobject.prop2.a ); // 1
In your example it's just returned as a nameless object.
return {children:{label:node.name, label:node.address}};
Means you are returning a new Object. The {} are the Object's constructor, and in this case its an Anonymous object.
Thank you both for the quick response. So if I understand your explanations correctly, the return statement is returning an anonymous object, and this object has only one property named "children", which is again an associative array - ok, here is the part I don't quite understand still, it seems that both properties in this array are named "label", is this allowed?

Resources