Let's assume two tables Boxand Item. Box may have many items, one item have only one box. I would like to fetch all items which have box is in given array. How could I do that? In CD I would do it by predicate and property in Item class which stands for connection to Box.
I am using version 0.81
UPDATE (10-27-2014)
Bidirectional relationships are now supported. See Realm's docs: http://realm.io/docs/cocoa/latest#inverse-relationships
ORIGINAL ANSWER
Bidirectional relationships must be explicitly linked at this time. Here's an example:
#class Box;
#interface Item : RLMObject
#property Box *box;
#end
RLM_ARRAY_TYPE(Item);
#interface Box : RLMObject
#property RLMArray<Item> *items;
#end
...
Item *item = [[Item alloc] init];
Box *box = [[Box alloc] initWithObject:#[#[item]]];
item.box = box;
We have plans to simplify this pattern in the future.
This answer was taken from GitHub
Related
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.
Cannot figure out why I get this error.
No visible #interface for 'RLMObject' declares the selector 'createOrUpdateInRealm:withValue:'
I have included the Realm/Realm.h header
Define my RLMObject in this manner
Class aClass = NSClassFromString(modelName);
RLMObject *m = [[aClass alloc] init];
Then I create a NSMutableDictionary to contain values which I want to partially update on the RLMObject.
NSMutableDictionary *updateValues = [[NSMutableDictionary alloc] init];
And then I call createOrUpdateInRealm:withValue: on m
[m createOrUpdateInRealm:realm withValue:updateValues];
But I get the error. I have no idea why this happens?
createOrUpdateInRealm:withValue: should be called on your subclass, not on an instance.
You should use it like this:
CustomObject *myCustomObject = [CustomObject createOrUpdateInRealm:realm withValue:dictionary];
where CustomObject is a subclass of RLMObject.
+createOrUpdateInRealm:withValue: is a class method of RLMObject, not an instance method. This means you need to call it on your subclass directly, not on an instance of your subclass:
[MyClass createOrUpdateInRealm:realm withValue:dictionary];
I'm facing a problem with a view-based NSTableView running on 10.8 (target is 10.7, but I think this is not relevant).
I'm using an NSTableView, and I get content values for my custom NSTableCellView through bindings. I use the obejctValue of the NSTableCellView to get my data.
I added a button to my cell, and I'd like it to trigger some action when clicked. So far I have only been able to trigger an action within the custom NSTableCellView's subclass.
I can get the row that was clicked like this, using the chain:
NSButton *myButton = (NSButton*)sender;
NSTableView *myView = (NSTableView*)myButton.superview.superview.superview;
NSInteger rowClicked = [myView rowForView:myButton.superview];
From there I don't know how to reach my App Delegate or controller where the action is defined.
As I am using cocoa bindings, I do not have a delegate on the NSTableView that I could use to trigger my action.
Do you have any idea how I could talked back to controller ?
Many thanks in advance!
Although you are using bindings you can still set your controller as the delegate for your tableview in the interface builder.
I see that you already are able to access the table view from inside your cell. The next task must be simple, just set the table view delegate as the target for your button's action.
Thanks for your question, I also will be triggering an action from a button on a NSTableView. Your question helped to put me on the correct path.
First to address the your solution to finding which row number my NSTableView is on. I was able to find it without knowing the button, in my custom NSTableView I installed the following as a first attempt:
- (NSInteger)myRowNumber
{
return [(NSTableView*)self.superview.superview rowForView:self];
}
this works fine, however it is less than robust. It only works if you already know specifically how deep you are in the view hierarchy. A more robust and universal solution is:
- (NSInteger)myRowNumber
{
NSTableView* tableView = nil;
NSView* mySuperview = self;
do
{
NSView* nextSuper = mySuperview.superview;
if (nextSuper == nil)
{
NSException *exception =
[NSException exceptionWithName:#"NSTableView not found."
reason:[NSString stringWithFormat:#"%# search went too deep.",
NSStringFromSelector(_cmd)] userInfo:nil];
#throw exception;
}
if ([nextSuper isKindOfClass:[NSTableView class]])
tableView = (NSTableView*)nextSuper;
else
mySuperview = mySuperview.superview;
} while (tableView == nil);
return [tableView rowForView:self];
}
this not only works at the NSTableView level, but works with anything installed at any level above it, no matter how complex the view hierarchy.
As to the unanswered part of your question, I established an IBOutlet in my class and using interface builder tied if to my files owner (in my case my document class). Once I had a reference to the class I was sending my message to, and the row number, I call the function. In my case the call required that I pass the row number it originates from.
[self.myDoc doSomethingToRow:self.myRowNumber];
I tested this and it works at various levels of the view hierarchy above NSTableView. And it functions without having to have the row selected first (which appears to be assumed in Apples documentation).
Regards, George Lawrence Storm, Maltby, Washington, USA
Use rowForView: and the responder chain
To respond to a control's action embedded within an NSTableCellView, the control should issue the action to the First Responder. Alternatively, File Owner is possible but this is more tightly coupled.
Use rowForView: within the action method to determine which row's control issued the action:
- (IBAction)revealInFinder:(id)sender {
NSInteger row = [self.tableView rowForView:sender];
...
}
The action is implemented within any of the responder chain classes. Most likely, this will be your subclassed NSWindowController instance. The responder could also be the application delegate; assuming the delegate has a means to talk to the NSTableView.
See Apple's example TableViewPlayground: Using View-Based NSTableView and NSOutlineView to see this in action.
Suhas answer helped me.
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "EDIT_CELL_VIEW"), owner: self) as? SymbolManagerCell {
if let editButton = cell.subviews[0] as? NSButton {
editButton.target = cell // this is required to trigger action
}
return cell
}
return nil
}
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à !
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.