'Use of Undeclared Identifier' in AppDelegate (iOS) - 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.

Related

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"

I'm pretty new to Objective C. Keep getting this error
"Use of undeclared identifier"
for this line of code:
NSString *textOut1 = textOut.text;
Obviously I am just trying to pull the textbox text. I have declared the following in my h file
#property (weak, nonatomic) IBOutlet UITextField *textOut;
So I cannot understand why I keep getting that damn error. Thanks!
Use this:
NSString *textOut1 = _textOut.text;
Checkout the extra underscore I added in front of textOut
Read the paragraph titled Most Properties Are Backed by Instance Variables in this apple documentation page.
To access the property textOut of an object referred to by the variable someVariable, you write someVariable.textOut. So to access the property textOut of the object that is self, you write self.textOut. You omitted the owner — self in this case.
self.textOut.text is what you need.
A property is basically something like a class variable in Java that requires a public getter and setter to work with. So you cannot use it in a .m file directly, but need to utilize the getter and setter. Objective C on iOS actually provides you with these methods by itself. Hence, when you create a property, under the hood, you have code that does a getter and setter by itself.
You can set the value as :
_textOut = BLAHBLAH
And get it as :
[self textOut.text]
or
self.textOut.text
or even _textOut.text (this is technically the local variable that is referenced by textOut)
Or in your case,
`NSString *textOut1 = [self textOut.text];`
or NSString *textOut1 = self.textOut.text;
or NSString *textOut1 = _textOut.text; // This is probably the least recommended one.
Though I believe the Stanford class says it is always better to do [self textOut].
If you are not (#synthesize) synthezising the property yourself then it will be synthesized with the instance variable having a Underscore at the start of the name.
try :
NSString *textOut1 = _textOut.text;

Purpose of Synthesize

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.

Fix warning: cannot pair a synthesized setter/getter with a user defined setter/getter

I use in my application QHTTPOperation.{h/m} found here all work properly but I got 8 warnings as follow:
Writable atomic property 'acceptableStatusCodes' cannot pair a
synthesized setter/getter with a user defined setter/getter
Writable atomic property 'acceptableContentTypes' cannot pair a
synthesized setter/getter with a user defined setter/getter
Writable atomic property 'authenticationDelegate' cannot pair a
synthesized setter/getter with a user defined setter/getter
...
I am asking because I have noticed that in the project of the above link there is no Warnings related to QHTTPOperation.{h/m}.
Any idea?
Thanks
declare the property nonatomic.
because the compiler does not verify a user-defined accessor's implementation is atomic or nonatomic, it assumes it is not atomic. this is a pretty safe assumption considering the actual implementation uses object level spin locks (in some cases), and the data which backs the implementation is abstracted from us. the only way we could fulfill the contact is by using the (private) runtime functions which the compiler uses, and then the compiler would have to verify the calls and parameters were correct in this scenario. thus, the user-defined accessor is not guaranteed to fulfill the standard objc runtime atomic contract.
Remove the #synthesize for these properties. They provided get/set.
EDIT: For clarity. In the .h, they declare acceptableStatusCodes with
NSIndexSet * _acceptableStatusCodes;
and
#property (copy, readwrite) NSIndexSet * acceptableStatusCodes;
Then, in the .m, they have
#synthesize acceptableStatusCodes = _acceptableStatusCodes;
and
- (NSIndexSet *)acceptableStatusCodes
{
return [[self->_acceptableStatusCodes retain] autorelease];
}
- (void)setAcceptableStatusCodes:(NSIndexSet *)newValue
{
if (self.state != kQRunLoopOperationStateInited) {
assert(NO);
} else {
if (newValue != self->_acceptableStatusCodes) {
[self willChangeValueForKey:#"acceptableStatusCodes"];
[self->_acceptableStatusCodes autorelease];
self->_acceptableStatusCodes = [newValue copy];
[self didChangeValueForKey:#"acceptableStatusCodes"];
}
}
}
These two blocks (the synthesize and the message implemenations) both define the same messages, so they are in conflict. The set message does an extra check at the beginning that the auto-generated synthesize will not do (the check for kQRunLoopOperationStateInited), so I would remove the synthesize, which is being ignored anyway.
The set message is correctly implementing copy semantics with
self->_acceptableStatusCodes = [newValue copy];
And it releases the old value. It also does keyValue change notification. I don't know why they left in the synthesize -- it looks like they might have wanted the state check later, and forgot to remove the auto-generated get/set.

Resources