I am quite new to Obj C and iOS development and I have come across an issue to which I have no understanding why it is happening.
So to set the scene, I have 2 model classes, Player and Computer Player and a Controller.
Player:
#interface Player : NSObject
-(void) playerMessage;
#end
ComputerPlayer:
#interface ComputerPlayer : Player
-(void) computerPlayerOnlyMessage;
#end
Controller:
#interface viewController : UIViewController{
Player *p1;
Player *p2;
Player *currentPlayer;
}
#implmentation ViewController
-(void)viewDidLoad
{
p1 = [[Player alloc]init];
p2 = [[ComputerPlayer alloc]init];
[p1 playerMessage];
currentPlayer = p2;
[currentPlayer computerPlayerOnlyMessage];
}
However the issue with the above is [currentPlayer computerPlayerOnlyMessage] gives a complier error when ARC is turned on. When ARC is turned off it gives a compiler warning but will run as I would expect it too.
Any help is appreciated to get help me figure why this behaviour is happening.
Isn't it better to define:
- (void)playerMessage;
method in ComputerPlayer class and:
-(void)playerMessage {
[super playerMessage];
[self computerOnlyPlayerMessage];
}
That's a point of inheritance, isn't it? You defined (expecting) your class variable as Player but NOT ComputerPlayer, and if it is ComputerPlayer it will execute specific work only for "computer".
Of course then you execute:
[Player playerMessage]; // Warning should gone
You can test, if it is a computer player
if ([currentPlayer isKindOfClass:[ComputerPlayer class]])
[(ComputerPlayer *)currentPlayer computerPlayerOnlyMessage];
It gives you an error because p2 is subclass of Player and you haven't for such a method as computerPlayerOnlyMessage in Player class. This method exists in ComputerPlayer class so you should declare p2 as a object of this type. Chenge line where you declare p2 to:
ComputerPlayer *p2;
First instead of declaring them as ivars like
#interface viewController : UIViewController{
Player *p1;
Player *p2;
Player *currentPlayer;
}
do it with #properties. The reason being is that ivars don't have any getters or setters whereas they are automatically generated if you use '#properties so change to
#interface viewController : UIViewController
// This will auto generate the ivars, getters and setters
#property (nonatomic, strong) Player *p1;
#property (nonatomic, strong) Player *p2;
#property (nonatomic, strong) Player *currentPlayer;
#end
then you can do
#implmentation ViewController
-(void)viewDidLoad
{
p1 = [[Player alloc]init];
p2 = [[ComputerPlayer alloc]init];
[p1 playerMessage];
currentPlayer = p2;
// Could also replace below with [currentPlayer isKindOfClass:[ComputerPlayer class]] use which ever fits best for you and what you want.
// If using below, if you decided to subclass ComputerPlayer class anything that subclassed
// from ComputerPlayer will also make it into this if statement. If iskindOfClass: is used
// Only objects that are kind of class will make it into this if statement.
if([[currentPlayer class] isSubclassOfClass:[ComputerPlayer class]]) {
[(ComputerPlayer *)currentPlayer computerPlayerOnlyMessage];
}
}
As #Greg said, computerPlayerOnlyMessage is a method exposed by the ComputerPlayer class, not the class it inherits from, so even if the compiler reports a warning when ARC is disabled, it would be a bad practice to use it.
Explicitly asking the class instance if it implements that method it's a workaround that works though. However in my opinion that solution lacks of good OO design, and I wouldn't use it unless I have a good reason (there are cases when it is handy) - in other OO languages that wouldn't event be possible.
Polymorphism allows an instance of a class to be used as if it were one of its super classes, but not the opposite. You can override and specialize the superclass methods, but you cannot expect a superclass to be aware of methods implemented by any of its subclasses.
I suggest 2 possible solutions:
declare computerPlayerOnlyMessage in the Player class as abstract (with empty body or throwing an exception, acting as a reminder that the method should be overriden in subclasses)
remove computerPlayerOnlyMessage from ComputerPlayer and instead override playerMessage. Thanks to polymorphism, the correct implementation will be called, regardless of whether you are accessing to the class instance as Player or ComputerPlayer
If computerPlayerOnlyMessage is meant to do what playerMessage does, just in a different way, I'd choose option no. 2
This seems like a good place to use protocols.
Here's how I might write your example, where I need to send "player" messages to all instances of Players, specialize on occasion, and send specific "npc" messages other times.
#protocol <NPC>
#property (nonatomic) NSString *someNPCString;
- (void)foo;
- (void)bar;
#end
#interface Player : NSObject
#end
#implementation Player
- (void)message
{
NSLog(#"message");
}
#end
#interface AI : Player <NPC>
#end
#implementation AI
#synthesize someNPCString;
- (void)foo
{
NSLog(#"foo");
}
- (void)bar
{
NSLog(#"bar");
}
#end
#interface viewController : UIViewController
#property (nonatomic) NSArray *humans;
#property (nonatomic) NSArray *npcs;
#end
#implmentation ViewController
-(void)viewDidLoad
{
id<Player> currentPlayer = nil;
humans = [NSArray arrayWithObject:[Player new]];
npcs = [NSArray arrayWithObjects:[AI new], [AI new], nil];
// message all player types, regardless of player or npc
for (Player *player in [humans arrayByAddingObjectsFromArray:npcs])
{
currentPlayer = player;
[player message];
if([player conformsToProtocl:#protocol(NPC)])
{
[(id<NPC>)player foo];
}
}
for (id<NPC>npc in npcs)
{
[npc bar];
npc.someNPCstring = #"str";
}
}
As you can see, this lets you treat npcs like human players, if you need to, let's you ask if the player conforms to the NPC protocol, so you may call the required protocol methods, and let's you reference objects specifically by their protocol.
Protocols begin to make the most sense, in my humble opinion, when you begin to need to "mix in" behavior to various objects.
Related
I want to write a custom delegate method to receive an event in one of my view controllers from another view controller. Should I use blocks here instead of delegates. Which is the preferred one ?
#protocol MyClassDelegate
-(void)doSomethingInDelegate;
#end
#interface MyClass : NSObject
#property id<MyClassDelegate> delegate;
-(void)doSomething
#end
#implementation MyClass
-(void)doSomething
{
[self.delegate doSomethingInDelegate];
}
#end
#interface MyOtherClass<MyClassDelegate> : NSObject
...
#end
#implementation MyOtherClass
-(void)doSomethingInDelegate
{
NSLog(#"Doing something in delegate");
}
#end
In most cases, if you have a very small number of delegate methods (ideally just 1), then blocks may be a good replacement. If you have several delegate methods, then blocks can become awkward.
UITableView has dozens of delegate methods between UITableViewDelegate and UITableViewDataSource. Configuring that with blocks would be unwieldy and make code reuse very difficult. If a particular way of "being the delegate" may be highly reusable (like in UITableViewController), then delegates are a much more powerful pattern.
On the other hand, if your delegate would wind up having just a single "thisActionFinished:` method, then a delegate is likely overkill and it's better to just pass a block. There are many cases that this is true, and we used to have to need to create a lot of one-method delegate protocols, and it was a bit of a pain. Blocks made that common pattern a lot easier.
But it's not a universal replacement for delegation, and blocks have many other purposes that have nothing to do with callbacks. So it's important to learn both techniques.
Looking to your specific example, there are several mistakes. Let's do it in both delegate and block forms.
Delegate
// Since the protocol needs to know about the class, you need to warn the
// compiler that this class exists.
#class MyClass;
// Declare the delegate protocol. Delegate method names should follow this
// pattern with "did", "should", or "will" in their names. Delegate methods
// should always pass the delegating object as the first parameter. A given
// delegate may be delegating for several instances.
#protocol MyClassDelegate
-(void)myClass:(MyClass *)class didSomething:(id)something;
#end
// Declare the class that has a delegate. Notice that `delegate` should be `weak`
// here. In your example, it's `strong`, and that will almost always lead to a
// retain loop. With rare exceptions, delegates are not retained.
#interface MyClass : NSObject
#property (nonatomic, readwrite, weak) id<MyClassDelegate> delegate;
-(void)doSomething;
#end
// Do the thing
#implementation MyClass
-(void)doSomething {
[self.delegate myClass:self didSomething:#"SOMETHING"];
}
#end
// The delegate object almost always has a strong pointer to the thing it delegates
// for. That's why you want the `delegate` property to be weak.
// Note that your syntax was wrong. "MyOtherClass <MyClassDelegate>". That's
// the new generic syntax, not the protocol syntax. Protocols go at the end.
#interface MyOtherClass : NSObject <MyClassDelegate>
#property (nonatomic, readwrite, strong) MyClass *c;
#end
// And the obvious impl
#implementation MyOtherClass
- (instancetype)init {
self = [super init];
if (self) {
self.c = [MyClass new];
self.c.delegate = self;
}
return self;
}
-(void)myClass:(MyClass *)class didSomething:(id)something {
NSLog(#"Doing something in delegate");
}
#end
Block
Let's do the same thing if this were a block-based API.
// If your callback takes no arguments and returns nothing, then you can
// use dispatch_block_t here. But often you need parameters or return
// something, and for that you should usually make a typealias. Welcome to the
// spiral world of block syntax.
typedef void(^MyClassCallback)(id something);
// Instead of a delegate, we have a callback. We might have several. We might
// have a block that returns the row height. But if you're doing a lot of
// that, just use a delegate. Note that blocks should always be `copy`.
#interface MyClass : NSObject
#property (nonatomic, readwrite, copy) MyClassCallback callback;
-(void)doSomething;
#end
// And here's how you use the block. It's just like a function.
#implementation MyClass
-(void)doSomething {
if (self.callback != nil) {
self.callback(#"SOMETHING");
}
}
#end
// And the delegate.
#interface MyOtherClass : NSObject
#property (nonatomic, readwrite, strong) MyClass *c;
#end
#implementation MyOtherClass
- (instancetype)init {
self = [super init];
if (self) {
self.c = [MyClass new];
// And here's the syntax for creating the block.
self.c.callback = ^(id something) {
NSLog(#"Doing something in delegate");
};
}
return self;
}
#end
Notice we don't need an extra method in the delegate just to hold one line of code, and we don't need to define a protocol. That's the big reason for the move to blocks for lightweight delegation. It keeps related code close together. But when the code gets complicated, "together" gets crazy, and blocks are not longer a good solution. Back to delegates, which do that very well.
I'm new to objective-c and found some OO features I have learned from other language is different in objective-c. The most confusing question for me until now is how to reimplement a property in subclass, or should I do this?
For example, I have two view controllers GameViewController and CardGameViewController.
#interface GameViewController : UIViewController {
Game *_game;
}
#property (nonatomic) Game *game;
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *cardButtons;
#property (weak, nonatomic) IBOutlet UILabel *scoreLabel;
#property (weak, nonatomic) IBOutlet UILabel *messageLabel;
#end
#interface CardGameViewController : GameViewController
#property (nonatomic) CardMatchingGame *game;
#end
CardMatchingGame is derived from Game. #property game in GameViewController is implemented like below:
- (Game *)game
{
if (!_game) {
_game = [[Game alloc] initWithCardCount:[self.cardButtons count]
usingDeck:[self createDeck]];
}
return _game;
}
I tried to reimplement #property game like below but got a warning in the return clause which said Incompatible pointer types returning 'Game *' from a function with result type 'CardMatchingGame *'.
- (CardMatchingGame *)game
{
if (!_game) {
_game = [[CardMatchingGame alloc] initWithCardCount:[self.cardButtons count]
usingDeck:[self createDeck]
matchThreshold:self.threshold.selectedSegmentIndex + 2];
}
return _game;
}
Is this the correct way of reimplementing a property in subclass? If not, what am I supposed to do?
You can't reimplement like that (well, you could do a ton of casting, but that isn't a good option).
One option is to create the property as #property (nonatomic) id game; and then it can hold any type of Game class (or subclass) that you have. And, because it is id type the compiler will assume that any method you try to call is valid. Obviously you could make mistakes which you won't find till later.
Another, better, option is to add a new property in the subclass as #property (nonatomic) CardMatchingGame *cardGame; and, in the subclass, when a new game is created the CardMatchingGame instance is stored in both game and cardGame properties. Now, the superclass has access to game and can use it, and the subclass has access to cardGame, which is typed as the correct class. So, you have compiler checks and usage of the same instance in both classes. But, you haven't reimplemented a property - you have multiple properties, each doing the appropriate task for their location + purpose.
If CardMatchingGame is a subclass of Game you can override - (Game *)game and return your CardMatchingGame object. Just make sure not to change the return type.
I think the problem is ivar in parent class Game *_game; it produce warning you see. Try to use different name or id type for it.
or just cast it before return (CardMatchingGame *)_game;
I am attempting to create an abstract class and inherit some of its properties in a subclass. If I leave the properties in the abstract class' header file, all of the properties are accessible. The problem is that the instance of the subclass can also access those properties, which is not always desirable in my case.
For instance, I have a delegate in my abstract class that sends down button presses to its sub class. I realize that this may not be the best way of structuring inheritance, so other suggestions are welcome. However, I would still like to know how my subclass can inherit some properties from its superclass without making all of those properties available in its instance. Thanks in advance!
Here is some example code below:
#interface AbstractClass : UIView
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
…
#protocol ButtonDelegate
#required
- (void) buttonWasPressed;
#end
…
#interface SubClass() <ButtonDelegate>
- (id)init {
self = [super init];
if (self) {
self.buttonDelegate = self;
}
return self;
}
-(void) buttonWasPressed {
[self doSomething];
}
…
#implementation ViewController
- (void)viewDidLoad {
SubClass *subClass = [[SubClass alloc] init];
subClass.buttonDelegate = self; // THIS IS NOT DESIRABLE
}
Do like UIGestureRecognizer does.
All public properties and methods goes into UIGestureRecognizer.h
All protected properties and methods goes into UIGestureRecognizerSubclass.h.
Only import this in the *.m-files. Never include it in any public header.
All private properties and methods goes into *.m-files. Use the #interface ClassName ()
Example https://gist.github.com/hfossli/8041396
how to my subclass can inherit some properties from its superclass
without making all of those properties available in its instance
What is the problem with this?
#import <Foundation/Foundation.h>
#interface Animal : NSObject
{
#protected
NSString *name; // default access. Only visible to subclasses.
}
#end
#implementation Animal
-(NSString*)description {
return name;
}
#end
#interface Cow : Animal
#end
#implementation Cow
-(id)init {
self=[super init];
if (self){
name = #"cow";
}
return self;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Cow *cow = [Cow new];
NSLog(#"%#", cow); // prints the name through internal access
// error accessing from the outside: NSLog(#"%#", cow.name);
Animal *animal = [Animal new];
// error accessing from the outside: NSLog(#"%#", animal.name);
}
}
Maybe I misunderstood the question, you say
Creating properties only visible to subclass in Objective-C
and then
The problem is that the instance of the subclass can also access those
properties
Which one is it?
Create an empty category on top of your implementation file (.m):
#interface AbstractClass()
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
In that way, your subclass will inherit and can access that property, but not other external classes because it's not in the header.
I don't think there is any way to achieve this using property declaration.
Either a property be visible for all (declared in .h file) or it will be invisible for all (declared in .m file using category)
I guess one way is declaring public/protected variable in .h file class declaration:
#interface AbstractClass : UIView {
...
id<ButtonDelegate>buttonDelegate;
...
}
#end
I am not sure about this, but give a try.
I see one approach that can fit your problem, however, it is pretty rude. Use Antonio's suggestion and create the private category with the property. As you've mentioned, it's scope is limited to the .m file. So you can put your subclasses into that file. This will be hard to read the code if subclasses are huge, but this is the only way for you as far as I understand.
EDIT: well, I have another solution. Copy
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
to all your subclasses. This will give you a warning about the absence of the property's #synthesize, but should work. I'd prefer this, if subclasses wont be changed or added often.
Let me describe how it would work.
We add a property into the Abstract class, and it is hidden for all (even for subclasses):
// .m file
#interface Abstract ()
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
#implementation Abstract
#synthsize buttonDelegate;
#end;
But due to runtime features of Objective-C we still can call for that property, and there will not be any runtime error, only compiler warning.
To get rid of that warning and to add an ability to autocomplete, we add property without #synthsize into all subclasses:
#interface MySubclass : Abstract
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
This will tell the compiler that there is such a property somewhere. There will be also one warning about the absence of #synthesize, but Xcode will still could autocomplete if you write something like
MySubclass *subclass = ...
subclass.butto...
It can not be done. There is no private or protected in objective-c. Stuff declared in the .m file "private" interface is only visible to that class and not in any subclass. Also you can always use your "private" properties/methods from outside if you want, although it would be bad practice to do so.
I am developing an ARC enabled project. From a view controller I am pushing MyClass,
- (void)pushMyClass {
MyClass *myClass = [[MyClass alloc] init];
[self.navigationController pushViewController:myClass animated:YES];
}
After doing some operations I am popping MyClass. The problem here is that MyClass is not getting deallocated. Following is how the classes look.
/* MyHelperClassDelegate */
#protocol MyHelperClassDelegate <NSObject>
- (void)helperDidFinishHelping:(MyHelperClass *)helper;
#end
/* MyHelperClass Interface */
#interface MyHelperClass : NSObject {
__weak id <MyHelperDelegate> delegate;
}
#property(nonatomic, weak) id<MyHelperDelegate> delegate;
- (void)startHelping;
#end
/* MyHelperClass Implementation */
#implementation MyHelperClass
#synthesize delegate;
- (void)dealloc {
delegate = nil;
}
/* MyClass */
#interface MyClass : UIViewController <MyHelperClassDelegate> {
MyHelperClass *helper;
}
#implementation MyClass {
- (void)dealloc {
helper.delegate = nil;
}
- (void)getHelp {
helper = [MyHelperClass new];
helper.delegate = self;
[helper startHelping];
}
- (void)helperDidFinishHelping:(MyHelperClass *)helper {
}
}
MyHelperClass calls a web service using NSMutalbleURLRequest & NSURLConnection to fetch some data and saves it to user defaults.
One thing to notice here is, if I comment the line helper.delegate = self;, then MyClass gets deallocated.
What to do to make MyClass get deallocated when it is popped out of navigation controller?
Thanks.
Your delegate code looks correct (except your use of an ivar, you don't show a #synthesize so you may have _delegate and delegate both). Its quite likely that something else is retaining MyClass. What I suggest you do is add a NSLog to your MyClass dealloc. Then push it, and immediately hit the back button and see if its dealloc'd or not. If not, then take a hard look at what you do in viewDidLoad et al and start commenting out sections of that code until you can get the dealloc.
Also, I assume you don't keep a strong reference in the class that pushes the MyClass object.
I agree with Chuck that one cannot say much from the code provided. But one reason why the MyClass object is not deallocated might be that it is retained by your helper object since delegate is declared as strong, and the MyClass object has the property helper also declared as strong. In this case you had a retain cycle, and none of them can be released.
The trick could possibly lie within the fact that you use NSURLConnection. It is not specified how you use this class with the code that you've provided, but please note the special considerations referenced in the NSURLConnection class reference:
Special Considerations: During the download the connection maintains a
strong reference to the delegate. It releases that strong reference
when the connection finishes loading, fails, or is canceled.
My situation is that I have a few different mini-games in my app. The games are listed in a table view, and when one of them is selected I create the corresponding game object. I need the game objects to have a common parent class, so that I can do common things such as pausing and resuming.
I have a generic GameScene class which has a generic GameLayer property:
#interface GameScene : CCScene {
}
#property (nonatomic, strong) GameLayer* gameLayer;
However each child class of GameScene has it's own type of GameLayer. So for example the SuperMarioBros_GameScene has a SuperMarioBros_GameLayer. The problems arise when I initialize the SuperMarioBros_GameScene:
-(id) init
{
if( (self = [super init])) {
self.gameLayer = (SuperMarioBros_GameLayer*)[SuperMarioBros_GameLayer node];
[self addChild: self.gameLayer];
SuperMarioBros_InputLayer *inputLayer = [SuperMarioBros_InputLayer node];
inputLayer.delegate = self.gameLayer; //ERROR (see below)
[self addChild:inputLayer z:1 tag:2];
}
return self;
}
In general each game will also have an input layer, which will send UI messages to the gameLayer. I get this error:
Assigning to 'id <SuperMarioBros_FireDelegate> from incompatible type GameLayer*
I understand this is happening because SuperMarioBros_GameLayer implements <SuperMarioBros_FireDelegate>, but GameLayer doesn't.
So my question is how do I make the GameScene class hold a polymorphic property that can be any subclass of GameLayer? Keeping in mind that each type of GameLayer may implement different protocols based on their corresponding input layers? Or maybe there's a better way to go about this?
Again, the end goal is to be able to make a call from the main game controller such as
[currentGameScene pause];
which will in turn do something like:
[self.gameLayer pauseGameLoop];
In the implementation file of the SuperMarioBros_GameScene class, you can override the property declaration of the gameLayer property in a class extension:
#interface SuperMarioBros_GameScene ()
#property (nonatomic, strong) SuperMarioBros_GameLayer *gameLayer;
#end
Then you should not get a compiler error anymore.
This will not create new getter or setter functions (these are still called in the superclass), and does not introduce a new instance variable as backing store. It only tells the compiler that self.gameLayer is an instance of the subclass in this implementation file.