Define #property in Protocol - iphone

I have a number of UIViewController subclasses and I want them to share the same property called session which handles a "is logged in" state.
I know that I could use a parent class but this is very explicit and so I was wondering if I could "enforce" the session property via a shared protocol.
I have never seen an explicit property defined in a protocol (obviously you could define the setter and getter), so is defining a property inside a protocol an advisable pattern?

#property can also appear in the declaration of a protocol or category.
Stated in the official apple documentation. So no problem there.

Yes, using a protocol it's possible to add a property:
#protocol MyProtocol <NSObject>
#property (nonatomic, retain) NSFoobar *baz;
#end
And #synthesize baz; in every class that adopts this protocol (or you can mark the declared property as optional using the #optional keyword).

You can have properties in a protocol, provided every class that conforms to your protocol have a corresponding #synthesize for that property, or provide a getter and setter.

In .h file:
#property(nonatomic,strong)UILabel *mylabel;
In .m file:
#synthesize mylabel = _mylabel;
compiler will create getter and setter for mylabel.
Ex ->
-(void)setMylabe:(UILabel *) mylabel { //setter
}
-(UIlabel*)mylabel { // getter
}

Related

How to use #protocol in AppDelegate iPhone app?

I am working in iPhone app with 5 screens. I want to refresh the values in the screen 4th in UITabBarController. I have added #protocol in AppDelegate but it is not calling. This is the first time am using #protocol could you please help me to solve this issue,
In AppDelegate.h
#protocol ReloadViewControllerDelegate <NSObject>
-(void) refreshViewController:(NSString *)result;
#end
id refreshViewControllerDelegate;
#property (nonatomic, retain) id refreshViewControllerDelegate;
and i have synthesized.
In AppDelegare.m
#synthesize refreshViewControllerDelegate;
if ([refreshViewControllerDelegate conformsToProtocol:#protocol(ReloadViewControllerDelegate)])
{
[refreshViewControllerDelegate performSelectorOnMainThread:#selector(refreshViewController:) withObject:#"YES" waitUntilDone:NO];
}// Control not come inside of if Condition.... From here i want to update the fourthViewController..
But control not go inside of the if condition. Could you please guide me where am doing wrong?
In my 4th ViewController.h
#import "AppDelegate"
#interface fourthViewController : UIViewController <ReloadViewControllerDelegate>
In my 4th ViewController.m
-(void) refreshViewController:(NSString *)result
{
NSLog(#"Result : %#", result);
}
Can anyone please help me to do this? Thanks in advance.
You need to declare your delegate like this:
#property (nonatomic, weak) IBOutlet id<ReloadViewControllerDelegate> delegate;
The id will work, but by using the <>, you can make sure that the delegate you assign is actually implementing the protocol, you might still have to make sure it responds to selector but that is only if some methods are declared as
#optional
make sure you synthesize it and most important make sure you set it, and it is not nil.
You're getting a warning because you are typing your delegate as an id. An id is a generic type, which means the compiler has no idea of what methods or properties might be available. In order to remove your warning, declare your delegate to be an NSObject:
#property (nonatomic, retain) NSObject <ReloadViewControllerDelegate> *refreshViewControllerDelegate;
By declaring as an NSObject, the compiler now knows about all the methods NSObject has, which will then allow you to call:
-performSelectorOnMainThread:withObject:waitUntilDone:
on your delegate without warnings. Good luck!
Try this:
#protocol ReloadViewControllerDelegate <NSObject>
-(void) refreshViewController:(NSString *)result;
#end
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (weak) id <ReloadViewControllerDelegate>refreshViewControllerDelegate;
#end
In AppDelegate.m
#implementation AppDelegate
#synthesize window, refreshViewControllerDelegate;
...
here Tab4ViewController is name of class.
if ([Tab4ViewController conformsToProtocol:#protocol(ReloadViewControllerDelegate)])
{
[refreshViewControllerDelegate performSelectorOnMainThread:#selector(refreshViewController:) withObject:#"YES" waitUntilDone:NO];
}
...
#end
#import "AppDelegate.h"
#interface Tab4ViewController<ReloadViewControllerDelegate>
...
#end
#implementation Tab4ViewController
...
appDelegate.refreshViewControllerDelegate = self;
...
#end
You are calling this code:
if ([refreshViewControllerDelegate conformsToProtocol:#protocol(ReloadViewControllerDelegate)])
But refreshViewControllerDelegate is this:
id refreshViewControllerDelegate;
conformsToProtocol checks to see if the object declares that it conforms to the protocol, which yours does not. If you want to specify conformity to a protocol you need to:
id<ReloadViewControllerDelegate> refreshViewControllerDelegate;
EDIT
OK, on the performSelectorOnMainThread problem... That method is provided in a category for NSThread, and is not declared in the NSObject protocol. So, if you want to call that, then you need to declare your type as NSObject, which conforms to your protocol.
NSObject<ReloadViewControllerDelegate> refreshViewControllerDelegate;
EDIT
OK, it looks like this is not a simple question about using a protocol, but a full tutorial. Since SO isn't the place for such, I'll try to give a brief one...
A protocol is an interface declaration.
#protocol ReloadChatViewControllerDelegate <NSObject>
- (void)refreshViewController:(NSString *)result;
#end
That says there is a new protocol in town, with the name ReloadChatViewControllerDelegate and it also conforms to the NSObject protocol. Any class that adopts the new protocol must provide an implementation of refreshViewController. You can make a protocol method optional, by putting in an #optional section.
#protocol ReloadChatViewControllerDelegate <NSObject>
- (void)refreshViewController:(NSString *)result;
#optional
- (void)optRefresh;
#end
Now, let's leave the adoption of the protocol for later. Say you are writing generic code, and you just want to know if the object you are given conforms to the protocol, and if so, invoke a method on it. Something like...
#interface Bar : NSObject
#property (nonatomic, weak) NSObject<ReloadChatViewControllerDelegate> *refreshViewControllerDelegate;
- (void)blarg;
#end
Now, the Bar class is providing a delegate property, so that it can be give some object that will help it do some work. However, that delegate object must at least be an NSObject, and conform to the ReloadChatViewControllerDelegate protocol.
Now, ObjC (and C) is quite permissive, so you can force an object to be any type you want, but then you deserve the crash you get. Now, when blarg is called, the delegate is notified to do some work.
Since the property type of the delegate already says it conforms to the given protocol, there is no need to check for conformity. We can just call the delegate method. Note that we must see if the object implements any optional protocol methods.
#implementation Bar
#synthesize refreshViewControllerDelegate = _refreshViewControllerDelegate;
- (void)blarg {
// Do something, then invoke the delegate
[self.refreshViewControllerDelegate
performSelectorOnMainThread:#selector(refreshViewController:)
withObject:#"YES"
waitUntilDone:NO];
if ([self.refreshViewControllerDelegate respondsToSelector:#selector(optRefresh)]) {
[self.refreshViewControllerDelegate optRefresh];
}
}
#end
However, if you want to be generic, and accept any object as a delegate (maybe you want to make it optional that the delegate conforms to some given protocol), then you can accept a plain id and then check to see it it conforms. In that case, you could declare your delegate as just an id (or some other type).
#property (nonatomic, weak) id refreshViewControllerDelegate;
Now, in your code, you need to check for conformity.
- (void)blarg {
// Do something, then invoke the delegate
if ([self.refreshViewControllerDelegate
conformsToProtocol:#protocol(ReloadChatViewControllerDelegate)]) {
[self.refreshViewControllerDelegate
performSelectorOnMainThread:#selector(refreshViewController:)
withObject:#"YES" waitUntilDone:NO];
if ([self.refreshViewControllerDelegate
respondsToSelector:#selector(optRefresh)]) {
[self.refreshViewControllerDelegate optRefresh];
}
}
}
OK, now you have a protocol defined, and you have code that calls methods on the protocol. Two caveats.
First, the delegate has to be set to an object. nil will respond false for any method, so it will of course not conform, nor do anything when sent any message.
Second, you have to make sure that your delegate declares conformity to the protocol. Just implementing the methods is not conformity. If a class does not explicitly specify that is conforms to a protocol, then conformsToProtocol will return false, even if it implements the methods of the protocol.
So, let's specify some class that will act as our delegate by conforming to the protocol.
#interface Foo : NSObject<ReloadChatViewControllerDelegate>
- (void)refreshViewController:(NSString *)result;
#end
#implementation Foo
- (void)refreshViewController:(NSString *)result {
NSLog(#"Look, ma, I'm refreshed with %#", result);
}
#end
It conforms to the protocol, provides an implementation for the mandatory method, and omits the optional one.
Now, if you ran this code, you should see that marvelous code in all its splendor.
Foo *foo = [[Foo alloc] init];
Bar *bar = [[Bar alloc] init];
bar.refreshViewControllerDelegate = foo;
[bar blarg];

Adding category method to NSObject, but getting warnings because it's not in the <NSObject> protocol when I call it

(I found some questions discussing the idea, but I didn't see a solution for my problem.)
I added this convenience method as a category to NSObject. (I've added other methods, so I'm still interested in an answer even if you disagree with this particular convenience method.)
#implementation NSObject (MyCategory)
- (void)performInvocationOnMainThread:(NSInvocation *)invocation waitUntilDone:(BOOL)waitForMainThread;
#end
Then I have a protocol I defined:
#protocol MyDelegateProtocol <NSObject>
- (void)myDelegateProtocolMethod;
#end
Then I declare the delegate as a property of my class that implements said protocol.
#property (nonatomic, assign) id <MyDelegateProtocol> delegate;
But when I try to call the NSObject method I added in my category like so
NSInvocation *invocation = [self.delegate invocationForSelector:#selector(someSelector:withArg:)];
I get this warning
'-performInvocationOnMainThread:waitUntilDone:' not found in protocol(s)
If I cast my delegate as (NSObject *) then I don't get the warning. What am I doing wrong? It didn't seem like I could (or should?) add methods to an existing protocol without creating a "sub protocol" and using it from then on. (Which kind of defeats the point of adding methods to NSObject in mind.)
NSInvocation *invocation = [(NSObject *)self.delegate invocationForSelector:#selector(someSelector:withArg:)];
Your category extends the NSObject class, not the NSObject protocol. While the class now has the method, it's not defined as part of the protocol, hence the warning.
That's why typecasting to the NSObject * pointer type works; you're casting to the NSObject class type, rather than something like id<NSObject> which means an arbitrary Objective-C object that conforms to the NSObject protocol.
You'll have to make an intermediate protocol (or "sub protocol") that extends the NSObject protocol:
#protocol ExtendedNSObject <NSObject>
- (void)performInvocationOnMainThread:(NSInvocation *)invocation waitUntilDone:(BOOL)waitForMainThread;
#end
Then have your delegate protocol extend that one instead:
#protocol MyDelegateProtocol <ExtendedNSObject>
- (void)myDelegateProtocolMethod;
#end
If I'm not wrong, you can keep the existing NSObject (MyCategory) implementation, and they'll play nice together.
when pass/expect this type, qualify it like so:
- (void)race:(NSObject<MyDelegateProtocol>*)arg;

iphone - setting a property on another class

I have a property declared on a class:
.h
#interface myClass : UIView {
BOOL doStuff;
}
#property BOOL doStuff;
.m
#synthesize doStuff;
this class is a delegate of another one. On the other class, I am trying to set this property, doing something like
[delegate setDoStuff:YES];
I receive an error telling me that "method -setDoStuff: not found..."
How do I declare the property on the class, so other classes can read and set them?
thanks.
is your delegate declared as type "id" ?
either you declare its true type MyClass delegate in the other class (which points to your myclass) or
declare a protocol that delegate has to implement id in declaration.
Last (but not right approach) is to typecast it [(MyClass)delegate doStuff].
Make sure that you’re importing your custom class’s header and that delegate is declared as an instance of that class.
you could also specify the name of setter function in #property.
#property (nonatomic,setter = setMyDoStuff,assign) BOOL doStuff;

Why should we declare variables for #property

I am newbie in Objective. As I read many tutorial, #property has a variable for a type, the same variable is declared in #inferface too. Is this needed?
Example
#interface MyInterface : NSObject
{
NSInteger myVaribale;
}
#property(retain) NSInteger myVariable;
Here myVariable is declared in both place.
since iOS 4, you can write
#interface MyInterface : NSObject {
}
#property(assign) NSInteger myVariable;
#implementation MyInterface
#synthesize myVariable;
#end
Meaning you can omit the NSInteger myVaribale in your interface declaration as long as you synthesize it in the .m (the synthesize will create setter, getter and instance variable)
A drawback is that you won't see the value of myVariable in Xcode's debugger.
As a note, the redeclaration of the ivar's type in the #property statement can also be useful if you want to declare the property as the immutable type of the ivar's, for instance:
#interface MyClass : NSObject
{
NSMutableArray *myArray;
}
#property (retain) NSArray *myArray;
In this instance, the ivar is actually stored as an NSMutableArray, so it can be altered during the object's lifecycle.
However this is an internal detail and if you don't want to "advertise" is as being mutable (changeable), you can make the type of the property the immutable type – in this case an NSArray.
Although this won't actually stop other code using the returned array as mutable, it is good convention and notifies other code that it shouldn't treat it in this way.
It's not an inconvenience but more a basic concept of objc: A class can have member variables. In OOP you normally define getter and setters for member variables which should be available to the outside. In objective-c you are encouraged to define getters/setters at any time (if they should be private, put their declarations into a private interface). To simplify this task, objective-c uses properties which are not more than a abbreviation. Additionally there are things like key-value-coding and -observing which are enabled by properties, but basically, they are just abbreviations for getters and setters.
Conclusion: Inside of #interface you declare members, outside methods including getters/setters (properties).

Object as a data member in Objective C

From what I have experienced it seems as if objects cannot be shared data members in objective c. I know you can init a pointer and alloc the object in each method but I cannot seem to figure out how one can say define a NSMutableString as a data member and allow all of the methods to use and modify its data as in c++. Is this true or am I missing something?
To define an instance variable (member), edit your .h file:
#interface MyClass : NSObject {
// ivars go here
NSObject *member;
}
// methods go here
#end
Then, in your .m file, from any instance method (one which begins with -), you can access this variable.
- (void)doThingWithIvar {
[member doThing];
}
If you want to access the variable from outside the object itself, you'll need accessors. You can do this easily with Obj-C properties:
#interface MyClass : NSObject {
// ivars go here
NSObject *member;
}
// methods go here
#property (nonatomic, retain) NSObject *member;
#end
And in the .m:
#implementation MyClass
#synthesize member;
// ...
#end
The #synthesize line creates getter/setter methods for the ivar. Then you can use property syntax:
MyClass *thing = ...;
NSLog(#"%#", thing.member); // getting
thing.member = obj; // setting
(Note that I specified (retain) for the #property; if your member isn't an Objective-C object you won't want that. And if your property's class has a mutable counterpart, you'll want (copy) instead.)
It sounds like you want to synthesize (create getter/setter methods) a property for a member variable. I just found this cheat sheet, go down to the section called, "Properties", should give a quick overview.
Other than that Apple's documentation should give you more info.