Why I cannot do self.strID=nil;? - objective-c

self.strID=nil;
It pops error saying:
reason: '-[BGFacebookHandler setStrID:]: unrecognized selector sent to instance 0x20525240'
* First throw call stack:
However, I declared the property as read write privately:
#property (nonatomic) NSString * strID;
The catch is it's also declared as read only publicly through protocol. Basically I am implementing that public property with a private property.
What's wrong with my approach?
Obviously I can do #synthesize, but doing so means using obsolete version of objective-c
This is a run time error. Not a compile error. The code compile just fine by the way.

Declaring your implementation property as part of your interface or a private extension changes nothing at runtime. There must me something else missing in your code because I have the following code fragment that works fine:
#protocol Facebook<NSObject>
- (NSString*) strID;
#end
#interface BGFacebookHandler : NSObject<Facebook>
#property (retain) NSString * strID;
#end
#implementation BGFacebookHandler
#end
int main (int argc, const char * argv[])
{
#autoreleasepool {
BGFacebookHandler *object = [[BGFacebookHandler alloc] init];
object.strID = #"Hello";
NSLog(#"strID = %#",object.strID);
}
return 0;
}

Related

explain how description method works in NSObject class

In NSObject.h header file, i have seen a method
+ (NSString *)description;
I knew that "+" sign before the method indicates that it is a class method
Here is my entire program
#import <Foundation/Foundation.h>
#interface A : NSObject
#end
#implementation A
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
A * aObj = [A new];
NSLog(#"%#",[A description]);//o/p: A
NSLog(#"%#",[aObj description]);//o/p: <A: 0x10010f5a0>
}
return 0;
}
I have used the description method with both class as well with instance of it and i got the o/p as well. why i have not received any error or warning while using a class method using an instance particularly in this case
[aObj description];//why this piece of code is working fine
Thank you in Advance
Because NSObject has two methods:
+ (NSString *)description; // Class method
- (NSString *)description; // Instance method
So when you do [A description] you're calling the class method (declared in NSObject Class), when you do [aObj description] you're calling the instance method (declared in NSObject Protocol).

Objective C Global Variable

Can anyone tell me where I'm going wrong here please.
I have created an NSobject called BeaconData. The header file is:
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <CoreBluetooth/CoreBluetooth.h>
#interface BeaconData : NSObject
#property (nonatomic, strong) NSMutableArray * jsonArray;
#property (nonatomic, retain) NSString * bMajor;
#property (nonatomic, retain) NSString * bMinor;
#property (nonatomic, retain) NSString * bUUID;
-(void) getData;
#end
The implementation file is then:
#import "BeaconData.h"
#define getDataURL #"http://www.eventav.biz/websitebeacons/library/json/files/beacons.txt"
#implementation BeaconData
#synthesize jsonArray, bUUID, bMajor, bMinor;
//Retrieve data
-(void) getData
{
extern NSString * bUUID;
extern NSString * bMajor;
extern NSString * bMinor;
NSURL * url = [NSURL URLWithString:getDataURL];
NSData * data = [NSData dataWithContentsOfURL:url];
jsonArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
//Loop through Json Array
for (int i = 0; i < jsonArray.count; i++)
{
bUUID = [[jsonArray objectAtIndex:i] objectForKey:#"i_uuid"];
bMajor = [[jsonArray objectAtIndex:i] objectForKey:#"i_major"];
bMinor = [[jsonArray objectAtIndex:i] objectForKey:#"i_minor"];
}
}
#end
Next I try to call the Global variable bMajor in the main viewController.m file and print it out - just to see if it works, like this:
- (void)viewDidLoad {
[super viewDidLoad];
extern NSString * bMajor;
NSInteger beaconMajorInt = [bMajor integerValue];
NSLog (#"Beacon bMajor is %li", (long)beaconMajorInt);
But all I get is the following error:
Undefined symbols for architecture x86_64:
"_bMajor", referenced from:
-[ViewController viewDidLoad] in ViewController.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
You have declared your bMajor variable as a class property. This means that you must instantiate an instance of your BeaconData class to access the variable unless you include a class method.
However, in your code I see that you also want to make these variables global. It is redundant to declare a variable as a class property and then try to make it global. In objective-c simply declaring a variable outside the implementation section will make it global for all modules that import the file with the declaration. You do it like this:
NSString *bMajor = #"Your String";
#implementation BeaconData
// YOUR CLASS CODE
#end
You're using the extern keyword incorrectly. It should be used in .h class files to let anything that imports it know that they have access to this variable. You also must declare it like I showed in the .m class file
.h looks like this:
extern NSString *bMajor;
#interface BeaconData : NSObject
#end
Just because you can do this doesn't mean you should. Based on your code I would suspect what you want to do is turn your -getData instance method into a class method for a singleton that allows the class to manage these "global" variables while keeping with good coding practice.
This SO Q/A should provide you exactly what you need to create your singleton. I recommend you do it this way.
Then in your viewController you would access these variables by getting an instance of your class using the class method.

Problems with subclasses inheriting class factory methods (Objective-C)

While I'm more than familiar with C#, I'm totally new at Objective C and iOS development. So I'm learning the language. What I don't understand is why the following code throws a compiler error (and yes, this is from the exercises at Programming with Objective C:
SNDPerson:
#interface SNDPerson : NSObject
#property NSString *first;
#property NSString *last;
+ (SNDPerson *)person;
#end
#implementation SNDPerson
+ (SNDPerson *)person
{
SNDPerson *retVal = [[self alloc] init];
retVal.first = #"Ari";
retVal.last = #"Roth";
return retVal;
}
#end
SNDShoutingPerson:
#import "SNDPerson.h"
#interface SNDShoutingPerson : SNDPerson
#end
#implementation SNDShoutingPerson
// Implementation is irrelevant here; all it does is override a method that prints a string
// in all caps. This works; I've tested it. However, if necessary I can provide more code.
// The goal here was for a concise repro.
#end
Main method:
- int main(int argc, const char * argv[])
{
SNDShoutingPerson *person = [[SNDShoutingPerson alloc] person]; // Error
...
}
The error is "No visible #interface for "SNDShoutingPerson" declares the selector "person".
Shouldn't this work? SNDShoutingPerson inherits from SNDPerson, so I would have assumed it got access to SNDPerson's class factory methods. Did I do something wrong here, or do I have to declare the method on SNDShoutingPerson's interface as well? The exercise text implies that what I did should Just Work.
Omit the +alloc when calling the class method:
SNDShoutingPerson *person = [SNDShoutingPerson person];
Briefly:
+ (id)foo denotes a class method. This takes the form:
[MONObject method];
- (id)foo denotes an instance method. This takes the form:
MONObject * object = ...; // << instance required
[object method];
Also, you can declare + (instancetype)person in this case, rather than + (SNDPerson *)person;.
change the line SNDShoutingPerson *person = [[SNDShoutingPerson alloc] person]; // Error
to
SNDShoutingPerson *person = [[SNDShoutingPerson alloc] init];
Cheers.
If you want to call class method:
SNDPerson person = [SNDPerson person];
person is a class method, but you're trying to call it with the incompletely constructed instance returned by alloc. Kill the alloc and just do [SNDShoutingPerson person].
This has nothing to do with subclasses, by the way. You would get the same error if you had written [[SNDPerson alloc] person].

Objective-C protocol property compiler warning

I can't get rid of compiler warning when I define property inside protocol. Strange thing is that I have two properties defined, and I only get warnings for the second one (which is object type, while the first property is value type).
Here is screenshot:
Can anyone tell me how to get rid of this warning, and why it is generated? The code is working normally, it is just this warning that annoys me :)
In your program, the property is called view. There must be a getter called view and a setter called setView. If you do not use #synthesize you must supply these two methods, and this is the reason of the compiler warning.
The code is working normally because you do not reference the property using dot notation or call the getter and setter methods.
Your issue is that the compiler cannot find an implementation for the properties you defined in the protocol.
For this reason, it is not recommended to add properties to a protocol, instead, you would define just a simple method to access the property, and one to set it. That would give you the proper error messages, and while you couldn't use dot-notation, it keeps the warnings in the right place.
Alternatively, you could do something like this (not recommended, but for educational reasons):
#import <objc/runtime.h>
#protocol myProto
#property (assign) int myProperty;
#end
#implementation NSObject(myProto)
-(int) myProperty
{
return [objc_getAssociatedObject(self, "myProperty") intValue];
}
-(void) setMyProperty:(int) myProperty
{
objc_setAssociatedObject(self, "myProperty", [NSNumber numberWithInt:myProperty], OBJC_ASSOCIATION_RETAIN);
}
#end
#interface MyObj : NSObject<myProto>
#end
#implementation MyObj
#dynamic myProperty;
#end
int main(int argc, char *argv[])
{
#autoreleasepool
{
MyObj *myObj = [MyObj new];
myObj.myProperty = 10;
NSLog(#"%i", myObj.myProperty);
}
}

how does readonly property work

I am reading: http://cocoacast.com/?q=node/103
I came across this method in the above page:
-(void)foo
{
self->iVar = 5; //legal because we are referencing a member variable
iVar = r; // illegal because we are referencing a readonly property
}
I then created a project in Xcode.
Test0.h
#import <Foundation/Foundation.h>
#interface Test0 : NSObject
{
#private int iVar;
}
#property (readonly, assign) int iVar;
- (void) foo;
#end
Test0.m
#import "Test0.h"
#implementation Test0
#synthesize iVar;
- (void) foo
{
iVar = 5;
}
#end
main.m
#import <Foundation/Foundation.h>
#import "Test0.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Test0 *t1 = [[Test0 alloc] init];
[t1 foo];
NSLog(#"%d", t1.iVar);
}
return 0;
}
The result in Console is 5.
My questions:
The web page mentioned above uses
self->iVar = 5
I have used iVar = 5
What difference does it make?
The web page mentioned above says
iVar = r; // illegal because we are referencing a readonly property
Is iVar = 5 (which I have used) not same as iVar = r ?
How is it not illegal?
how does readonly property work?
The compiler simply does not generate or verify the existence of the setter. It will generate the getter, and that property may be backed by an ivar. As well, the setter is not declared in the class interface.
self->iVar = r;
vs
iVar = r;
What difference does it make?
None. They are identical. They are both direct assignment of the ivar. It's similar to other languages, when adding a superfluous scope resolution (e.g. this->).
The difference is when you attempt to use the setter method (e.g. self.prop = val or [self setProp:val];). In this case, the compiler will emit a warning and the runtime would throw an exception (unless you or a subclass defined the setter yourself).
The web page mentioned above says iVar = r; // illegal because we are referencing a readonly property.
That's wrong. Direct access to the ivar of a readonly property is fine if the ivar exists. You don't see an error in this case because you're accessing the ivar directly, rather than using the setter.
Other issues:
The article incorrectly states atomics are 'mutexed'.
The article incorrectly states atomic properties guarantee thread safety.