RLMArray properties in unmanaged RLMObjects in Objective-C - objective-c

I cannot find a good example code of this anywhere....but the information I find is contradictory and confusing...
#interface DAORealmMetadata : RLMObject
#property (nonatomic, copy) NSString* id;
#end
RLM_ARRAY_TYPE(DAORealmMetadata)
#interface DAORealmBase : RLMObject
#property (nonatomic, copy) NSString* id;
#property (nonatomic, copy) RLMArray<DAORealmMetadata*><DAORealmMetadata>* metadata;
#end
RLM_ARRAY_TYPE(DAORealmBase)
Question:
Am I supposed to add #dynamic metadata in the DAORealmBase implementation...or not?
I've tried it with and without and have the same end result...a crash.
I create the unmanaged object with this code:
DAORealmBase* baseObj = [[DAORealmBase alloc] init];
DAORealmMetadata* metadataObj = [[DAORealmMetadata alloc] init];
[baseObj.metadata addObject:metadataObj];
Question:
Why does the last line cause a crash/exception?
I can only assume that I"m doing something wrong, but I cannot find any specifics as to what I did.
Thanks!

Well, I tracked the problem down, and through some trial and error, determined that the problem was the property attributes on the RLMArray properties.
Changing
#property (nonatomic, copy) RLMArray<DAORealmMetadata*><DAORealmMetadata>* metadata;
to
#property RLMArray<DAORealmMetadata*><DAORealmMetadata>* metadata;
seems to have resolved the problem. I believe specifically the 'copy' attribute.
Now, I know that the Realm docs say that the attributes are ignored and not needed, but the lint checker I'm using wants them there...and since they are "ignored", what's the harm?
Well, they are ignored on normal Realm properties, but on the RLMArray properties they aren't ignored, and problems ensue.
Hopefully this will help someone else in the future and save them some time.

Related

Realm RLMArray is nil

For some reason my RLMArray's are nil when I run my program.
I am able to see the data in the RLM browser, and it links appropriatley.
Is there something I could be missing here?
#interface HMFAlbum : RLMObject
#property NSInteger persistentId;
#property RLMArray<HMFTrack> *tracks;
#property RLMArray<HMFRange> *ranges;
#end
#interface HMFTrack : RLMObject
#property NSInteger persistentId;
#property HMFAlbum *album;
#end
RLM_ARRAY_TYPE(HMFTrack)
#interface HMFRange : RLMObject
#property NSInteger persistentId;
#property (readonly) RLMLinkingObjects *albums;
#end
RLM_ARRAY_TYPE(HMFRange)
It's expected that instance variables of persisted RLMObject instances will be nil as the property getters read values directly from the Realm file. The instance variables are only used for objects prior to being saved to the Realm, and remain nil after that point.
The Debugging section of the Realm documentation touches on this topic and mentions an LLDB script that can be used to show property values of persisted objects when debugging in Xcode. The -description method on the model classes, used by NSLog when formatting objects using the %# format specifier, will also show the property values as expected.

Why iOS cannot get subviews property for class UIView using class_getProperty function?

I want to get the information about subviews property of class UIView:
objc_property_t property = class_getProperty([UIView class], "subviews");
But, it returns nil? I think it is so strange. Could someone explain this behavior to me?
Weird. If you use -valueForKey:, it can clearly be shown to exist. This used to be a bug with the old LLVM clang compiler in Xcode 3.2.3, where properties in categories (yes, it is declared in a category on UIView) wouldn't get recognized by the runtime, and there was even a bug report filed here about it. I know recent versions of Xcode have been having trouble with categories of late...
I just write a test code:
#interface Cat : NSObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic) NSInteger age;
#property (nonatomic, readonly, copy) NSArray *subviews;
#end
It is ok. So Apple maybe be do so magic on it I guess.

"Expected a type" error pointing to the return type of a method

I've attempted to compile, but every time I do, one method throws a strange "expected a type" error. I have a method in the header:
-(ANObject *)generateSomethingForSomethingElse:(NSString *)somethingElse;
The error points at the return type for this method. I've imported ANObject into the header using #import "ANObject.h" and ANObject is compiling fine..
Why is this happening?
This is to do with the order that the source files are compiled in. You are already probably aware that you can't call a method before it is defined (see below pseudocode):
var value = someMethod();
function someMethod()
{
...
}
This would cause a compile-time error because someMethod() has not yet been defined. The same is true of classes. Classes are compiled one after the other by the compiler.
So, if you imagine all the classes being put into a giant file before compilation, you might be able to already see the issue. Let's look at the Ship and BoatYard class:
#interface BoatYard : NSObject
#property (nonatomic, retain) Ship* currentShip;
#end
#interface Ship : NSObject
#property (nonatomic, retain) NSString* name;
#property (nonatomic, assign) float weight;
#end
Once again, because the Ship class has not yet been defined, we can't refer to it yet. Solving this particular problem is pretty simple; change the compilation order and compile. I'm sure you're familliar with this screen in XCode:
But are you aware that you can drag the files up and down in the list? This changes the order that the files will be compiled in. Therefore, just move the Ship class above the BoatYard class, and all is good.
But, what if you don't want to do that, or more importantly, what if there is a circular relationship between the two objects? Let's increase the complexity of that object diagram by adding a reference to the current BoatYard that the Ship is in:
#interface BoatYard : NSObject
#property (nonatomic, retain) Ship* currentShip;
#end
#interface Ship : NSObject
#property (nonatomic, retain) BoatYard* currentBoatYard;
#property (nonatomic, retain) NSString* name;
#property (nonatomic, assign) float weight;
#end
Oh dear, now we have a problem. These two can't be compiled side-by-side. We need a way to inform the compiler that the Ship* class really does exist. And this is why the #class keyword is so handy.
To put it in layman's terms, you're saying, "Trust me man, Ship really does exist, and you'll see it really soon". To put it all together:
#class Ship;
#interface BoatYard : NSObject
#property (nonatomic, retain) Ship* currentShip;
#end
#interface Ship : NSObject
#property (nonatomic, retain) BoatYard* currentBoatYard;
#property (nonatomic, retain) NSString* name;
#property (nonatomic, assign) float weight;
#end
Now the compiler knows as it compiles BoatYard, that a Ship class definition will soon appear. Of course, if it doesn't, the compilation will still succeed.
All the #class keyword does however is inform the compiler that the class will soon come along. It is not a replacement for #import. You still must import the header file, or you will not have access to any of the class internals:
#class Ship
-(void) example
{
Ship* newShip = [[Ship alloc] init];
}
This cannot work, and will fail with an error message saying that Ship is a forward declaration. Once you #import "Ship.h", then you will be able to create the instance of the object.
I found this error hapenning when there is circular dependency on the headers. Check if the .h file where you declare this method is imported in ANObject.h
You basically add
#class ANObject;
before #interface!
So, for some reason I was getting this error while trying to set a method with an enum type in the parameters. Like so:
- (void)foo:(MyEnumVariable)enumVariable;
I had previously used it like this and never had an issue but now I did. I checked for circular dependency and could find none. I also checked for typos multiple times and no dice. What ended up solving my issue was to adding 'enum' before I wanted to access the variable. Like so:
- (void)foo:(enum MyEnumVariable)enumVariable;
{
enum MyEnumVariable anotherEnumVariable;
}
Usually when I see an error like this it's because I have a typo on a previous line, such as an extra or missing parenthesis or something.
It may sound stupid, but wrong shelling or wrong use of uppercase/lowercase letterwrong case this.
I got this message, when the variable type was misspelled. See below this below
e.g.
-(void)takeSimulatorSafePhotoWithPopoverFrame:(GCRect)popoverFrame {
instead of.....
-(void)takeSimulatorSafePhotoWithPopoverFrame:(CGRect)popoverFrame {
Strangely enough, changing the order of my imports has fixed this in the past... Try moving the import to the bottom after all your other imports.
I solved it by adding #class class_name to the .h file

Class declaration in Objective C. What is the difference? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Properties and Instance Variables in Objective-C 2.0
Objective-C Properties with or without instance variables
What is the difference between the following two pieces of code? Both are compilable and I don't know which is "correct".
#interface JTPlayer : NSObject {
NSString *userId;
NSString *name;
BOOL inBattle;
}
#property (nonatomic, copy) NSString *userId;
#property (nonatomic, copy) NSString *name;
#property (nonatomic, assign) BOOL inBattle;
#end
and
#interface JTPlayer : NSObject
#property (nonatomic, copy) NSString *userId;
#property (nonatomic, copy) NSString *name;
#property (nonatomic, assign) BOOL inBattle;
#end
One is the previous version of declaring properties. As you can see, you needed to declare variables by hand, and then declare properties applied to those variables.
The second is the newer version that manages the rest for you, declaration of variables and correspondences with properties.
Both blocks are correct, but the first one requires more keystrokes. This code (both versions) is supposed to belong to a header file, accompanied with a source file with .m extension that contains the implementation. This implementation will contain #synthesize instructions, that generate the getter and setter methods for you.
For more information, you really should read the Apple Guide to Objective-C. Also check out http://www.raywenderlich.com .
The current version of the Objective-C runtime does not require you to specify you instance variables for properties. #synthesize will add them for you automatically.
Check out this article that I put up awhile ago. It explains about instance variables and properties.
Objective-C Properties with or without instance variables

How to store blocks in properties in Objective-C?

I'd like to store objective-c block in a property for later use. I wasn't sure how to do it so I googled a bit and there is very little info about the subject. But I've managed to find the solution eventually and I've thought that it might be worth sharing for other newbies like me.
Initially I've thought that I would need to write the properties by hand to use Block_copy & Block_release.
Fortunately I've found out that blocks are NSObjects and - copy/- release is equivalent to Block_copy/Block_release. So I can use #property (copy) to auto generate setters & getters.
Edit: updated for ARC
typedef void(^MyCustomBlock)(void);
#interface MyClass : NSObject
#property (nonatomic, copy) MyCustomBlock customBlock;
#end
#implementation MyClass
#end
MyClass * c = [[MyClass alloc] init];
c.customBlock = ^{
NSLog(#"hello.....");
}
c.customBlock();
Alternatively, without the typedef
#property (copy, nonatomic) void (^selectionHandler) (NSDictionary*) ;
You can find a very good explanation of this in WWDC 2012 session 712 starting in page 83. The correct way of saving a block under ARC is the following:
#property(strong) my_block_type work;
Be careful with the retain cycles. A good way to solve is set the block to nil when you do not need it anymore:
self.work = nil;