Purpose of Synthesize - ios

I am using an iOS5 book to learn iOS programming.
#synthesize coolWord;
^synthesize is used for all properties in .m files
I heard that in iOS6 there is no need for synthesize, since it is automatically done for you. Is this true?
Does synthesize play any role for iOS6?
Thanks for the clarification. :)

#synthesize in objective-c just implements property setters and getters:
- (void)setCoolWord:(NSString *)coolWord {
_coolWord = coolWord;
}
- (NSString *)coolWord {
return _coolWord;
}
It is true with Xcode 4 that this is implemented for you (iOS6 requires Xcode 4). Technically it implements #synthesize coolWord = _coolWord (_coolWord is the instance variable and coolWord is the property).
To access these properties use self.coolWord both for setting self.coolWord = #"YEAH!"; and getting NSLog(#"%#", self.coolWord);
Also note, both the setter and getter can still be manually implemented. If you implement BOTH the setter and getter though you NEED to also manually include #synthesize coolWord = _coolWord; (no idea why this is).

Autosynthesis in iOS6 still requires #synthesize
to generate accessor methods for properties defined in a #protocol.
to generate a backing variable when you included your own accessors.
The second case can be verified like this:
#import <Foundation/Foundation.h>
#interface User : NSObject
#property (nonatomic, assign) NSInteger edad;
#end
#implementation User
#end
Type: clang -rewrite-objc main.m and check that the variable is generated. Now add accessors:
#implementation User
-(void)setEdad:(NSInteger)nuevaEdad {}
-(NSInteger)edad { return 0;}
#end
Type: clang -rewrite-objc main.m and check that the variable is NOT generated. So in order to use the backing variable from the accessors, you need to include the #synthesize.
It may be related to this:
Clang provides support for autosynthesis of declared properties. Using
this feature, clang provides default synthesis of those properties not
declared #dynamic and not having user provided backing getter and
setter methods.

I'm not sure how #synthesize relates to iOS6 but since Xcode 4.0, it's essentially been deprecated. Basically, you don't need it! Just use the #property declaration and behind the scenes, the compiler generates it for you.
Here's an example:
#property (strong, nonatomic) NSString *name;
/*Code generated in background, doesn't actually appear in your application*/
#synthesize name = _name;
- (NSString*)name
{
return _name;
}
- (void) setName:(NSString*)name
{
_name = name;
}
All that code is taken care of the complier for you. So if you have an applications that have #synthesize, it's time to do some cleanup.
You can view my similar question here which might help to clarify.

I believe that #synthesize directives are automatically inserted in the latest Obj-C compiler (the one that comes with iOS 6).
The point of #synthesize pre-iOS 6 is to automatically create getters & setters for instance variables so that [classInstance getCoolWord] and [classInstance setCoolWord:(NSString *)aCoolWord] are generated. Because they are declared with #property, you also get the convenience of dot syntax for the getter and setter.

hope this will help little more
yes previously we have to synthesis the property by using #synthesis now it done by IDE itself.
but we can use it like
// what IDE does internally
#synthesis name=_name;
we use _name to access particular property but now you want synthesis by some other way like
firstname you can do it like
#synthesis name= firstname
or just by name
#synthesis name=name

With automatic synthesis in iOS6, it is no longer necessary to specifically declare backing ivars or write the #synthesize statement. When the compiler finds a #property statement, it will do both on our behalf using the guidelines we’ve just reviewed. So all we need to do is declare a property like this:
#property (nonatomic, strong) NSString *abc;
and in iOS 6, #synthesize abc = _abc, will be added automatically at compile time.

Related

Allow change in property only from one specific class

Suppose I have a class Participant which looks like this
Participant.h
#interface Participant : NSObject
#property(nonatomic, readonly) NSString *name;
#property(nonatomic, readonly) NSString *id;
#end
Here properties are readonly because I don't want anyone using this interface to change it
Besides ParticipantManager.h
What changes should I do in Participant class and how would I create ParticipantManager such that only ParticipantManager can change properties of Participant
More context
I get an event from react-native when value changes. to keep things in sync, I want my interface ParticipantManager to only change the values.
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
#interface ParticipantManager : RCTEventEmitter <RCTBridgeModule>
#end
^^ Above class should only be able to change properties of Participant class
For a user to change a value, he would call changeName method, which will send an event back to react-native where react-native would change value and send back to native code
what I have tried.
So, I thought about using class extensions concept but I am getting an error.
Here is what I did
I create Participant+Private.h which implements setName method
#import " Participant.h"
interface Participant()
- (void)setName:(NSString)name
- (void)setId:(NSString)name
#end
PS: I implemented setName and setId method in Participant.h
- (void)setName:(NSString)name {
_name = name;
}
but then when I am using it in my ParticipantManager.h, it is throwing error
No visible #interface for Participantdeclares the selector
setName
I am using it like this
#import "Participant+Private.h"
NSString* value = #"varun";
[[Participant sharedInstance] setName:value];
Can someone help me in fixing error?
Slightly detailed question here:
No visible #interface for Participant declares the selector setName
Objective-C doesn't provide that sort of reasoned privacy, e.g. "I am private to everyone except one other specific class which I hereby name". (Actually, I don't know any language that behaves that way, but that's not to say that there are no such languages of course.)
If this is a framework, you can use #package privacy to confine the privacy of something to other classes in the same framework.
Otherwise, Objective-C generally solves the visibility problem by importing headers, so if you put public accessors for Participant into a header and the only class that imports that header is ParticipantManager, then only ParticipantManager sees them.

Understanding why assign is breaking code in swift

I made an xcframework (in objective c) which is working fine in objective C but throws an error when using swift.
On debugging, I realized that it was breaking in swift because I was using assign.
I went through his answer: https://stackoverflow.com/a/4511004/10433835
where they say this
In most cases you'll want to use weak so you're not trying to access a deallocated object
I didn't quite get what assign does, but I don't think I am trying to access a deallocated object.
This is what I am doing
I have config with these properties
#import <Foundation/Foundation.h>
#interface Config : NSObject
#property(nonatomic, assign, readwrite) NSString *name;
#property(nonatomic, assign, readwrite) NSString *id;
#property(nonatomic, assign, readwrite) NSString *api;
#end
This is my Config.m file
#implementation Config
- (id)init {
if (self = [super init]) {
_api = #"https://api.xyz.in"
}
return self;
}
- (NSMutableDictionary *_Nonnull)configProperties {
if (!_name) {
[NSException raise:#"name" format:#"Room name cannot be null, please set room name"];
}
NSLog(#"Room name: %#", _name);
At this line it will throw Thread 1: EXC_BAD_ACCESS
NSLog(#" name: %#", _name);
if I remove assign, it won't throw any error
How am I calling it?
let config:Config = Config();
config.name = "varun_bindal";
let props = config.configProperties()
Can someone please explain me why using assign in swift is crashing my code? and why not using it doesn't.
You actually don't want a weak or assign set for that property. The object will be deallocated as soon as it is set. You want a strong reference because the object owns the property. weak will nil the pointer as soon as it's set. So checking the pointer will return nil. assign will keep the address of the pointer without keeping the actual memory set. Hence you're pointing to something that has been deallocated. ie: pointing to bad memory location. It's kind of a remnant of the old days really..
You can read here for more info on keywords:
https://exceptionshub.com/property-and-retain-assign-copy-nonatomic-in-objective-c.html
The answer is: It's complicated.
Swift takes care of object ownership for you. Your only responsibility is to create strong or weak variables to avoid retain cycles. When you stay in Swift, it takes care of everything else.
Life is more complicated in Objective-C, and more complicated still when you need to have Objective-C and Swift code interact.
In order for Swift and Objective-C to work correctly together, you have to declare the memory semantics of your Objective-C classes correctly.
When you declare an Objective-C property as assign, you're telling the compiler not to do any memory management on it. Your Swift code won't set up strong references, and won't be notified if the object has been deallocated. If the Objective-C code doesn't need it any more and releases it, and your Swift code tries to reference it, you will crash.
(As mentioned in comments, Objective-C's assign is equivalent to unowned in Swift.)
As Larme says, assign is ok for non-object scalar types, but not for objects.

How to create a new object and assign properties in Objective-C?

I'm trying to bridge an Objective C SDK with React Native and I'm having some trouble. I have a Subclass of NSObject and I'm trying to set some property values but I can't get it to work.
I have tried to change the property in the header, and in the imp file with out any difference.
PrinterSDK.h (which has libPrinterSDK.a)
#interface Printer : NSObject
#property (nonatomic, readonly) NSString* name;
#property (nonatomic, readonly) NSString* UUIDString;
#end
RNPosPrint.m
#interface Printer ()
#property (readwrite) NSString* name;
#property (readwrite) NSString* UUIDString;
#end
RCT_EXPORT_METHOD(printTestPaper:(NSString*)name:(NSString*)uuid)
{
Printer* printer = [[Printer alloc] init];
printer.name = name;
}
But I keep facing issue with the setter for some reason I can't figure out.
ExceptionsManager.js:94 Exception '-[Printer setPrinterName:]: unrecognized selector sent to instance 0x13fd25b90' was thrown while invoking printTestPaper on target RNPosPrint with params (
"Test Printer",
"XXX-XXX-XXX"
)
You do not report the names of your .h and .m files or what else is in the .m – e.g. #implementation of Printer? The class printTestPaper belongs to? Without details like this it is difficult for anyone to help you, you need to help people help you.
That said some points that may help you:
The #interface Printer () where you open up the properties to be writeable should be in the your Printer.m file – in general do not try to open up access to a type's properties from outside the type's implementation, it is both bad design and may not work as you hope (as you just found out).
The code to support a #property is generated by the compiler when it compiles the #implementation, #interface's themselves produce no executable code – they describe the accessible parts of the #implementation.
setter=<name> provides a different name for the auto-created property setter function. While a method <name> will be created to set the property using dot syntax the properties name is still used, e.g. in your case printer.name = ... is still used even with the setter=setPrinterName:. You can call the auto-created method using standard method syntax, that failed in your case for the reasons above.
Using setter=<name> or getter=<name> are really advanced features and you probably will never need to use them – when you do need to use them you will know! Just avoid them till then.
If you wish to provide a method which creates the object and sets properties then do this in the type's implementation. The usual way of doing this is to provide an init method that does this, e.g. in this case it might be - initWithName:(NSString *)printerName { ... }, or an equivalent class method which does the allocation and sets the parameters, e.g. in this case it might be + newWithName:(NSString *)printerName { ... }.
HTH
Since it's an interface from statically linked library it is simply not possible to extend or manipulate. Not without tempering with the compiler.

'Use of Undeclared Identifier' in AppDelegate (iOS)

Running into a bit of an issue.
This is my first time really dealing significantly with an AppDelegate.h/.m file.
I've declared a property #property float centerFreq in AppDelegate.h. Then I synthesize it in AppDelegate.m like so: #synthesize centerFreq = _centerFreq. However, when I try to actually use centerFreq later on in AppDelegate.m, I get the error "Use of undeclared identifier 'centerFreq'". I don't understand why I can't use this variable anywhere in my .m file.
foo = self.centerFreq will call the getter that is automatically created. Equivalent to foo = [self centerFreq]. _centerFreq will access the instance variable (iVar) directly. In general, if you have created an #property you want to use the accessor methods centerFreq and setCenterFreq, which are called if you use self.centerFreq as the lvar or rvar in an assignment operation. (self.centerFreq = foo calls [self setCenterFreq:foo]).
#synthesize centerFreq = _centerFreq is unnecessary unless you have implemented both the getter and setter methods for the #property, as _centerFreq is the default name for the backing iVar. If you wanted to choose a different name for the iVar, then #synthesize would be useful.

How do I flag a method as deprecated in Objective-C 2.0?

I'm part of a team developing a fairly large iPad app and there are many different classes we've created as a result. The trouble is some of the methods are now pretty much obsolete and I don't want simply remove them yet as I know some parts of the overall system use the methods... but there are better (newer) variants available which should be used instead (some of the old ones actually call the new ones, but the overall class interface is getting messy).
Is there a way in which I can mark certain methods as deprecated (like #deprecated in Java and [Obsolete] in .NET).
I see that Apple uses Availability.h and have tags such as
__OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA,__MAC_NA,__IPHONE_2_0,__IPHONE_3_0);
... is this the only way to do it (+ is it App Store safe to do this?) or are there alternatives which will flag a warning in XCode?
Deprecation Syntax
Syntax is provided to mark methods as deprecated:
#interface SomeClass
-method __attribute__((deprecated));
#end
or:
#include <AvailabilityMacros.h>
#interface SomeClass
-method DEPRECATED_ATTRIBUTE; // or some other deployment-target-specific macro
#end
IMHO, it's easier to write __deprecated:
- (void)myDeprecatedMethod __deprecated;
- (int)methodNameDeprecated:(int)param __deprecated;
Works too on classes
__deprecated
#interface MyDeprecatedClass
// ... some properties and methods ...
#end
If you want to give additional message with the deprecation flag, you can use following flags.
#property (strong, nonatomic) NSString *catName
__deprecated_msg("use name instead.");
// -- Or --
#property (strong, nonatomic) NSString *catName
DEPRECATED_MSG_ATTRIBUTE("use name instead.");
// -- Or --
#property (strong, nonatomic) NSString *catName
__attribute__((deprecated("use name instead.")));
Using above mentioned flags, you can tell why you are deprecating or what is the method developer should use in future.
To mark a method as deprecated, use __attribute__((deprecated("Your message goes here")))
A practical example, from Mantle
#interface NSValueTransformer (UnavailableMTLPredefinedTransformerAdditions)
+ (NSValueTransformer *)mtl_externalRepresentationTransformerWithModelClass:(Class)modelClass __attribute__((deprecated("Replaced by +mtl_JSONDictionaryTransformerWithModelClass:")));
+ (NSValueTransformer *)mtl_externalRepresentationArrayTransformerWithModelClass:(Class)modelClass __attribute__((deprecated("Replaced by +mtl_JSONArrayTransformerWithModelClass:")));
#end
Use the deprecated attribute:
- (int)bar: (int)x __attribute__((deprecated));

Resources