"Use of undeclared identifier" - ios

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;

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' 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.

Assign Enum to Variable in Objective-C

How can I assign an enum to a variable and access its value later? I thought this would be pretty simple, but every time I try to assign the enum value to a variable (no type mismatches or warnings in Xcode appear) my app crashes with an EXC_BAD_ACCESS error.
Here's how I setup my enum in my header file (BarTypes.h):
typedef enum {
BarStyleGlossy,
BarStyleMatte,
BarStyleFlat
} BarDisplayStyle;
No issues there (reading and using the values at least). However, when I create a variable that can store one of the enum values (BarStyleGlossy, BarStyleMatte, or BarStyleFlat) then try to set that variable, the app crashes. Here's how I setup and use the variable:
//Header
#property (nonatomic, assign, readwrite) BarDisplayStyle barViewDisplayStyle; //I've also tried just using (nonatomic) and I've also tried (nonatomic, assign)
//Implementation
#synthesize barViewDisplayStyle;
- (void)setupBarStyle:(BarDisplayStyle)displayStyle {
//This is where it crashes:
self.barViewDisplayStyle = displayStyle;
}
Why is it crashing here? How do I store the value of an enum in a variable? I think the issue has to do with a lack of understanding about enums on my end, however if I follow conventional variable setup and allocation, etc. this should work. Any ideas on what I'm doing wrong?
Please note that I'm new to enums, so my vocabulary here may be a bit mixed up (forgive me - and feel free to make an edit if you know what I'm trying to say).
I found a few references about enums across the web:
What is a typedef enum in Objective-C?
Using enum types as properties in Objective C
How to create global enum
How do I define and use an ENUM in Objective-C?
I also tried searching Apple's Developer site but only came up with results about types for Apple APIs (ex. Foundation, UIKit, etc.)
EDIT: Here's how I call the setupBarStyle method:
BarView *bar = [[BarView alloc] init];
[bar setupBarStyle:displayStyle];
Just in case anyone out there is still trying to figure out how to assign an enum value to an enum typed variable or property...
Here is an example using a property.
In the header file...
#interface elmTaskMeasurement : NSObject
typedef NS_ENUM(NSInteger, MeasurementType) {
D,
N,
T,
Y,
M
};
#property(nonatomic) MeasurementType MeasureType;
#end
In the file where the object is created...
elmTaskMeasurement *taskMeasurement = [[elmTaskMeasurement alloc] init];
taskMeasurement.MeasureType = (MeasurementType)N;
The method you implement is called setupBarStyle:, but you call setupBarShape: on the object.
I had this error myself but the error was caused by a different bug I off course create myself.
The setter of my property "myApplicationState" was as follows:
-(void)setApplicationStyle:(myApplicationStyle)applicationStyle{
self.applicationStyle = applicationStyle;
//some more code
}
Off course this would result in an endless loop because in the setter, the setting is called again, and again, and again.
It had to be:
-(void)setApplicationStyle:(myApplicationStyle)applicationStyle{
_applicationStyle = applicationStyle;
//some more code
}

valueForKey: on packed struct?

Given the following packed struct:
typedef struct __attribute__((packed)) {
BOOL flag;
int x;
} Foo;
And the following class:
#interface Obj : NSObject
#property (nonatomic) Foo foo;
#end
#implementation Obj
#end
Trying to call valueForKey: on a property which has type of packed struct:
Obj *obj = [Obj new];
id boo = [obj valueForKey:#"foo"];
causes a crash inside valueForKey: (actually it's crashing not inside valueForKey: but in random places depending on moon magnitude, I guess it's memory corruption).
If I remove __attribute__((packed)) it works fine.
Any possibility to get struct's data without a crash? Is it Apple's bug?
PS. I do need to do it at runtime, i.e. I can't just call .foo directly, I only have #"foo" string at runtime. (What I'm trying to achieve actually is to recursively print object contents).
I don't know if this is possible with properties, but if it is I don't think you're using the right syntax.
Have you tried changing
id boo = [obj valueForKey:#"foo"];
to read
Foo boo = obj.foo;
?
Foo is not nor never will be an id. valueForKey: returns id, and the runtime might be barfing trying to squeeze struct Foo into an NSValue.
If you need to use valueForKey: for some reason, your accesses need to look like.
Foo myFoo = FooFactory();
Object *myObj = [Object new];
[myObj setValue:#( myFoo ) forKey:#"foo"];
Foo myFooOut;
[[myObj valueForKey:#"foo"] getValue:&myFooOut];
//I bet `getValue:` is where things are barfing.
In this case, if NSValue's machinery indeed can't handle the packed struct, you just have to write the accessors the old fashioned way: -<key> and -set:`.
PS: Never name a class "Object", there actually is an Object in some SDKs that NSObject inherits from. I assume that's just in your example.
Avoid KVO for your usage case, and stick to the handy dandy <objc/runtime.h> header. You can re-implement a basic part of KVO using this kind of introspection. Struct packing is used primarily to make sure the compiler doesn't align internal fields properly so the CPU does not need to handle it at the hardware level during execution. In this day and age, it's better to let the compiler take care of things for you.
If you'd really prefer this struct packing (as you said, in a network transmission scenario), I'll need further information to determine where the issue lies. Perhaps attempt to change #property (nonatomic) Foo foo; to #property (nonatomic) NSValue *foo; and then box it and unbox it yourself? This way, the exception/error will be in your application's domain.

Resources