why do other properties need nullability type specifier - objective-c

I am getting the date when a photo was created using
#property(nonatomic, readonly, nullable) AVMetadataItem *creationDate;
in my .h file. Then I get the value of the AVMetadataItem of my video asset.
This works fine however when I add this to my .h file all the rest of my properties get a warning that they are missing a nullability type specifier, even though they don't need it when I don't have this property listed. How do I do this without having to add a nullablity specifier to every other property etc. in the .h file?

Once you add a nullability annotation, ObjC expects that you have audited the file. To mark regions of the file to be nonull by default, use the NS_ASSUME_NONNULL_BEGIN and NS_ASSUME_NONNULL_END macros.
From the Nullability and Objective-C blog post:
NS_ASSUME_NONNULL_BEGIN
#interface AAPLList : NSObject <NSCoding, NSCopying>
// ...
- (nullable AAPLListItem *)itemWithName:(NSString *)name;
- (NSInteger)indexOfItem:(AAPLListItem *)item;
#property (copy, nullable) NSString *name;
#property (copy, readonly) NSArray *allItems;
// ...
#end
NS_ASSUME_NONNULL_END
// --------------
self.list.name = nil; // okay
AAPLListItem *matchingItem = [self.list itemWithName:nil]; // warning!
This will replace all the ! types in your Swift bridging with explicit non-optional types. You should audit the code to make sure this is correct. But for the common case, where most things are nonnull, the macros greatly simplify adoption.

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.

Can the memory management of a property change if it's redefined in a class extension?

If I have a property like this:
//test.h
#interface test
#property (nonatomic, readonly, weak) NSObject x;
#end
redefined in the implementation file to be read/write:
// test.m
#interface test ()
#property (nonatomic, readwrite) NSObject x;
#end
I used weak in .h, but I said nothing in the extension, will the property keep the 'weak' specifier, or will it change to 'strong'?
Will the keywords strong/assign/weak be overwritten when the property is redefined?
A simple test with Xcode 5.1.1 shows the weak attribute is kept. The same is true for the assign and strong attributes - you can specify them in the .h and omit them in the .m, if you do include them in the .m the two must match.
Having said that, I do not know if this is documented anywhere. But then the semantics of Objective-C are not formally defined anywhere either. So use at your own risk.
Recommendation: just repeat it.

#property and #synthesize

I'm very new to Objective C. (Two days now). When read about #synthesize, it seemed to overlap with my understanding #property (which I thought I understood) ... So, some details need to be ironed out in my mind ... it's bugging me.
Please correct me if I'm wrong about differences of #property and #synthesize:
If you declare a #property in your #interface, then you're telling the world that users can expect to use standard getters and setters for that property. Futhermore, XCode will make generic getters and setters for you. ... BUT, To what degree does that happen with the #property declaration? ( I.E. does that mean "completely" ... like unseen declarations for it in your #interface, and also unseen code in your #interface?
-Or-
Does #property take care of the unseen code declarations in your #interface only - whereas #synthesize takes care of the unseen code implementation in your #implementation section? )
First, note that the latest version of Xcode does not require #synthesize at all anymore. You can (and should) just omit it. That said, here's what the pieces do.
#property is a declaration of accessors. It is just a declaration. There is very little difference between the following:
#property (nonatomic, readwrite, strong) NSString *something;
vs.
- (NSString *)something;
- (void)setSomething:(NSString)aSomething;
The main difference is that declaring these methods using #property lets the compiler automatically generate (synthesize) the implementations for you. There is no requirement that you let the compiler do it for you. You are absolutely free to implement something and setSomething: by hand, and it is common to do. But, if you don't implement them by hand, the compiler will automatically create an ivar for you called _something and create a reasonable implementation for the getter and setter.
In older versions of Xcode, you had to explicitly request the auto-generation using the #synthesize keyword. But that is no longer required. Today, the only reason to use #synthesize is if you want the ivar to have a non-standard name (never do that).
A key point here is that the methods something and setSomething: are just methods. There is nothing magical about them. They're not special "property methods." They're just methods that by convention access a piece of state. That piece of state is often stored in an ivar, but does not need to be.
To be even more clear: object.something does not mean "return the ivar named _something from object." It means "return the result of [object something], whatever that does." It is common for that to return the value of an ivar.
You should declare all of your state (internal and external) using #property declarations, and you should avoid directly declaring ivars. You should also always access your properties via their accessors (self.something), except in the init and dealloc methods. In init and dealloc, you should directly use the ivar (_something).
#property declares a property on your class with whatever atomicity and setter semantics you provide.
With Xcode 4.4, autosynthesis is available wherein you are provided with a backing ivar from your property without declaring it in #synthesize. This ivar has the form of _propertyName where your property name is propertyName.
Objective-C #property and #synthesize
#property
generates get/set method
today(from Xcode v4.4 with the LLVM v4.0) #property additionally uses #synthesize inside
#synthesize propertyName = _propertyName
#synthesize:
generates a new iVar or link with existing iVar
generates an implementation of the get/set method with an appropriate iVar
[Case when #synthesize can be used]
#property
#interface SomeClass : NSObject
#property NSString *foo;
#end
//generated code
#interface SomeClass : NSObject
- (NSString *)foo;
- (void)setFoo:(NSString)newFoo;
#end
#synthesize pattern
#synthesize <property_name> = <variable_name>;
//Using
//1. Specify a variable. New variable(variableName) will be generated/linked with existing
#synthesize propertyName = variableName
//if variableName is not exist it generates:
//NSString *variableName;
//read access
NSString *temp = variableName;
//2. Default. New variable(propertyName - the same name as a property) will be generated/linked with existing
#synthesize propertyName
//is the same as
//#synthesize propertyName = propertyName
//if propertyName is not exist it generates:
//NSString *propertyName;
//read access
NSString *temp = propertyName;
//if you specify not-existing <property_name> you get
//Property implementation must have its declaration in interface '<class_name>' or one of its extensions
previously you had to use next syntax:
#interface SomeClass : NSObject
{
//1. declare variable
NSString *_foo;
}
//2. create property
#property NSString *foo;
#end
#implementation SomeClass
//3. link property and iVar
#synthesize foo = _foo;
#end
But today you can use next syntax
#interface SomeClass : NSObject
//1. create property
#property NSString *foo;
#end
Next, the same code, will be generated for both cases
#interface SomeClass : NSObject
{
//variable
NSString *_foo;
}
//getter/setter
- (void)setFoo:(NSString *)newFoo;
- (NSString *)foo;
#end
#implementation SomeClass
- (void)setFoo:(NSString *)newFoo
{
_foo = newFoo;
}
- (NSString *)foo
{
return _foo;
}
#end

XCode: Unrecognized selector sent to instance

I am getting the following error:
"-[Order items]: unrecognized selector sent to instance 0x6b5f240"
I do have a class called Order, which looks like this:
Order.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class OrderItem;
#interface Order : NSManagedObject {
#private
}
#property (nonatomic, retain) NSNumber * orderID;
#property (nonatomic, retain) NSDate * date;
#property (nonatomic, retain) NSNumber * orderCode;
#property (nonatomic, retain) NSSet* items;
#end
Order.m
#import "Order.h"
#import "OrderItem.h"
#implementation Order
#dynamic orderID;
#dynamic date;
#dynamic orderCode;
#dynamic items;
...
It doesn't extend any sort of class which has an "items" method, if I'm reading that correctly?
Is there any other reason I would be getting such an error. To add to the madness, this project is copied directly from a previous project, with some minor edits. I've done text comparisons on every single class in both projects and there are no differences other than the cosmetic changes I've made.
#dynamic items tells the compiler that you will be providing the methods for items.
Since this was working in a previous project, it must have had the following method somewhere in the .m file:
- (NSSet *)items {
// Appropriate code
}
If you do not want to provide your own custom getter like this, then change #dynamic items to #synthesize items and the compiler will generate one for you.
For more details, see the Declared Properties section of The Objective-C Programming Language provided by Apple here: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html
EDIT
While everything above still applies to a normal object (and may still apply here), I just noticed that this is a subclass of NSManagedObject.
In your old data model there was probably a relationship called items and therefore the appropriate methods were provided by NSManagedObject and #dynamic was appropriate to prevent compiler warnings.
If in your new data model there is no relationship named items, then the methods will not be generated and it will cause the problem that you are getting here.

How to define and implement properties in protocol

I want to define one protocol with few properties and need to use those properties in another NSObject subclass. Please give me link or example code. I need that to work with 10.5.
Thanks
PLEASE CHECK THE FOLLOWING SAMPLE CODE
#protocol MyProtocol
#property (nonatomic, readonly) id someObject;
#property (nonatomic, getter=isAlive) BOOL alive;
#end
#import "MyProtocol.h"
#interface MyCustomClass : NSObject <MyProtocol>{
}
#end
#import "MyCustomClass.h"
#implementation MyCustomClass
#synthesize someObject,alive;
/*
- (id)someObject {
return nil;
}
- (BOOL)isAlive {
return YES;
}
- (void)setAlive:(BOOL)aBOOL {
}
*/
#end
**Added:
Compling code with x86_64 architecture works fine. But error if i'll change the architecture to i386, then i am getting following warnings:
MyCustomClass.m:13: error: synthesized property 'someObject' must either be named the same as a compatible ivar or must explicitly name an ivar
error: synthesized property 'alive' must either be named the same as a compatible ivar or must explicitly name an ivar
I just want to know why it is working in x86_64 with #synthesize and not in i386.**
#property just says to the compiler that the class is expected to define the methods to match that property.
#protocol MyProtocol
#property (nonatomic, readonly) id someObject;
#property (nonatomic, getter=isAlive) BOOL alive;
#end
Anything implementing that protocol will now need to have
- (id)someObject;
- (BOOL)isAlive;
- (void)setAlive:(BOOL)aBOOL;
I think the things you're dealing with are primarily side effects of the introduction of Objective-C 2.0. It lets you do things like declare properties without also defining instance vars. But (as you have discovered), it is only x86_64 and post-10.5 compatible.