Is there a way to use something like
if (carRecord.status == CarRecord.statusRepaired) { // using a class constant
// ...
}
such as in a car repair shop, the carRecord object's state status is checked against the CarRecord class's constant. In Objective-C, is there such a way?
You would typically do this with an enum. For example:
//=== CarRecord.h:
typedef enum CarRecordStatus {
CarRecordStatusBroken = 0,
CarRecordStatusRepaired
} CarRecordStatus;
#interface CarRecord (NSObject) {
CarRecordStatus _status;
}
#property (nonatomic, assign) CarRecordStatus status;
#end
//=== CarRecord.m:
#implementation CarRecord
#synthesize status=_status;
- (void)someMethod {
if (self.status == CarRecordStatusRepaired) {
//...
}
}
#end
Here is how would you define it in .h file :
typedef enum CarRecordStatus {
CarRecordStatusBroken = 0,
CarRecordStatusRepaired,
} CarRecordStatus;
#interface MyClassName : NSObject
..interfacebody..
#end
Use it inside MyClassName or any other just import it that's it.
Related
I am looking to structure my unit tests in the correct way and would like to know how to approach testing a class method while passing an object into the method
So the method in question (basic example)
MyClient.m:
#import "MyClient.h"
#interface MyClient()
#property (nonatomic, strong) MyMedia *myMedia;
#end
- (void)setMedia:(MyMedia *)media {
self.MyMedia = media;
int var;
if (media && media.isLive) {
var = 1;
}
else {
var = 2;
}
}
}
So in this example i would create two tests, 1 that tests var is 2 if media.isLive and the other to check var is 2 if not.
Hopefully this makes sense
Thanks
Your code is not really testable because everything you would need to check is private. Whilst there are ways to 'hack' into a class using the runtime and stuff to test things, you really want to just utilise the publically access interface of your class. So I've re-written your code like this:
MyClient.h
#interface MyClient:NSObject
#property (nonatomic, strong) MyMedia *myMedia;
#property (nonatomic, assign, readonly) int var;
#end
MyClient.m
#import "MyClient.h"
#implementation MyClient
- (void)setMedia:(MyMedia *)media {
_MyMedia = media;
_var = media && media.isLive ? 1 : 2;
}
#end
Now lets do some tests using XCTest.
MyClientTests.m
#import XCTest;
#import "MyClient.h"
#interface MyClienTests:XCTestCase
#end
#implementation MyClientTests {
MyClient *_myCLient;
MyMedia *_media;
}
-(void) setUp {
_myClient = [[MyClient alloc] init];
_media = [[MyMedia alloc] init];
}
-(void) testMyClientMediaIsAlive {
_media.alive = YES;
_myClient.media = _media;
XCTAssertEqual(1, _myClient.var);
}
-(void) testMyClientMediaIsNotAlive {
_myClient.media = _media;
XCTAssertEqual(2, _myClient.var);
}
-(void) testMyClientNoMedia {
XCTAssertEqual(2, _myClient.var);
}
#end
I have a class which internally uses an ivar. I don't want to expose the ivar in the public interface of the class (the header) but I declare and use it in the implementation file, like so:
//--------SomeClass.h--------------
#interface SomeClass : NSObject
#end
//--------SomeClass.m--------------
#implementation SomeClass ()
{
#protected
NSMutableDictionary *_privateData;
}
#implementation SomeClass
// ...
#end
Then in a subclass of SomeClass, I try to access _privateData:
//--------SomeSubClass.m--------------
#implementation SomeSubClass
// ...
- (void)someMethod {
NSLog(#"%#", _privateData); // NOPE
NSLog(#"%#", self->_privateData); // NOPE
NSLog(#"%#", super->_privateData); // NOPE
}
// ...
#end
But I can't. Is there a way to do this?
In order to achieve the desired behavior, you should create a subclass header file which declares all of your protected data and #import it in your subclass' .m file.
MammalSubclass.h:
#interface Mammal () {
#protected
NSMutableDictionary *_privateData;
}
//...
#end
Human.m:
#import "Human.h"
#import "MammalSubclass.h"
#implementation Human //subclasses Mammal
- (void)someMethod {
NSLog(#"%#", _privateData);
}
//...
#end
I have a class in a game that is often used, and I thought it would be nice to tidy it up by grouping together instance variables with a typedef struct. I'm not completely convinced yet this will help or not.
Originally in my class header interface I had something like this:
#interface ThingClass : CCLayer {
#public
bool _invulnerableToggled;
int _invulnerableCount;
int _invulnerableMax;
}
#property(nonatomic, assign) bool invulnerableToggled;
#property(nonatomic, assign) int invulnerableCount;
#property(nonatomic, assign) int invulnerableMax;
and in my .m
#synthesize
invulnerableToggled = _invulnerableToggled,
invulnerableCount = _invulnerableCount,
invulnerableMax = _invulnerableMax;
A subclass of this class would set these variables to their default values in init. Another class could access an instance of this subclass and set the values accordingly with regular dot notation, like tempThing.invulnerableToggled = YES;
Now that I'm using a typedef struct, it looks as though my values cannot be adjusted, and I've tried various things to overcome it. Although it may be because I'm not setting this up correctly to begin with, so just in case I'll show you what I'm doing now.
Currently my class header:
typedef struct {
bool toggled;
int count;
int max;
} Invulnerable;
#interface ThingClass : CCLayer {
#public
Invulnerable _invulnerable;
}
#property(nonatomic, assign) Invulnerable invulnerable;
and in my .m
#synthesize
invulnerable = _invulnerable;
I set these values in a subclass init like so:
_invulnerable.toggled = NO;
_invulnerable.count = 0;
_invulnerable.max = 50;
When I try to set this in another class, I expect it to add 1 to the current value. It always remains 1 instead. This if statement is sometimes checked 60 times a second, but has not change to the count:
Invulnerable invulnerable = tempBaddy.invulnerable;
// check baddy invulnerability and increment if needed
if(invulnerable.toggled == YES){
int increase = invulnerable.count +1;
invulnerable.count = increase;
NSLog(#"invulnerable.count = %i", invulnerable.count);
}
This is not a common way in ObjC but you can pass the struct by reference, i.e. return a pointer to the struct:
#interface ThingClass : CCLayer {
#protected
Invulnerable _invulnerable;
}
#property(nonatomic, readonly) Invulnerable* invulnerable;
#end
The *.m file:
#implementation ThingClass
- (Invulnerable*)invulnerable {
return &_invulnerable;
}
#end
Updating the data:
Invulnerable* invulnerable = tempBaddy.invulnerable;
// check baddy invulnerability and increment if needed
if(invulnerable->toggled == YES){
invulnerable->count++;
NSLog(#"invulnerable.count == %i", tempBaddy.invulnerable->count);
}
I guess you are trying to perform some action on an instance of ThingClass (or its subclass). And the action affects the value of _invulnerable. In this case a more common way would be having a method in the Thing class that performs all the required updates:
#implementation ThingClass
- (void)headshot {
if (_invulnerable.toggled) {
_invulnerable.count++;
} else {
[self die];
}
}
#end
I have 2 classes one includes methodA and the other include methodB. So in a new class I need to override the methods methodA and methodB. So how do I achieve multiple inheritance in objective C? I am little bit confused with the syntax.
Objective-C doesn't support multiple inheritance, and you don't need it. Use composition:
#interface ClassA : NSObject {
}
-(void)methodA;
#end
#interface ClassB : NSObject {
}
-(void)methodB;
#end
#interface MyClass : NSObject {
ClassA *a;
ClassB *b;
}
-(id)initWithA:(ClassA *)anA b:(ClassB *)aB;
-(void)methodA;
-(void)methodB;
#end
Now you just need to invoke the method on the relevant ivar. It's more code, but there just isn't multiple inheritance as a language feature in objective-C.
This is how I code singletonPattern as "a parent" Basically I used a combination of protocol and category.
The only thing I cannot add is a new "ivar" however, I can push it with associated object.
#import <Foundation/Foundation.h>
#protocol BGSuperSingleton
+(id) singleton1;
+(instancetype)singleton;
#end
#interface NSObject (singleton) <BGSuperSingleton>
#end
static NSMutableDictionary * allTheSingletons;
+(instancetype)singleton
{
return [self singleton1];
}
+(id) singleton1
{
NSString* className = NSStringFromClass([self class]);
if (!allTheSingletons)
{
allTheSingletons = NSMutableDictionary.dictionary;
}
id result = allTheSingletons[className];
//PO(result);
if (result==nil)
{
result = [[[self class] alloc]init];
allTheSingletons[className]=result;
[result additionalInitialization];
}
return result;
}
-(void) additionalInitialization
{
}
Whenever I want a class to "inherit" this BGSuperSingleton I just do:
#import "NSObject+singleton.h"
and add #interface MyNewClass () <BGSuperSingleton>
Do you know about Protocols, protocols is the way to implement the multiple inheritance
I am trying to write a cocoa touch static library.
To keep it simple I would prefer not to use private variables within my interface file.
The code right now looks like this:
interface file (myView.h):
#interface myView: UIView {
NSTimer * myTimer;
}
#end
implementation file (myView.h)
#implementation myView
#end
This NSTimer pointer is just a private variable so I tried this:
(not working)
interface file (myView.h):
#interface myView: UIView {
}
#end
implementation file (myView.h)
NSTimer * myTimer;
#implementation myView
#end
It seems to work however it turned out that the timer is now a static variable.
Am I doing sth wrong or is there no solution?
You can't define instance variables in your implementation file.
A possible solution is to have a private structure containing the private variables and have one publicly declared private variable pointing to this private structure:
#interface MyView {
void *privateData;
}
Implementation file:
typedef struct {
NSTimer *myTimer;
} PrivateData;
#implementation MyView()
#property (readonly) PrivateData *privateData;
#end
#implementation MyView
- (id) init {
if (self = [super init]) {
privateData = malloc(sizeof(PrivateData));
self.privateData->myTimer = nil; // or something else
}
return self;
}
-(PrivateData *) privateData {
return (PrivateData *) self->privateData;
}
- (void) myMethod {
NSTimer *timer = self.privateData->myTimer;
}
- (void) dealloc {
// release stuff inside PrivateData
free(privateData);
[super dealloc];
}
#end
It's not beautiful, but it works. Maybe there are better solutions.
Just a note; trying to hide iVar's for the sake of security is silly. Don't bother.
For simplicity's sake, though, it has value.
However, a couple of solutions:
(1) If targeting iPhone OS or 64 bit Cocoa, you can #synthesize the ivar:
Foo.h:
#interface Foo:NSObject
#property(readwrite, copy) NSString *publiclyReadwriteNoiVar;
#property(readonly, copy) NSString *publiclyReadonlyPrivatelyReadwriteNoiVar;
#end
Foo.m:
#interface Foo()
#property(readwrite, copy) NSString *privateProperty;
#end
#implementation Foo
#synthesize publiclyReadwriteNoiVar, publiclyReadonlyPrivatelyReadwriteNoiVar, privateProperty;
#end
(2) Use a private subclass kinda like class clusters:
Foo.h:
#interface Foo:NSObject
#end
Foo.m:
#interface RealFoo:Foo
{
.... ivars here ....
}
#end
#implementation RealFoo
#end
#implementation Foo
+ (Foo *) convenienceMethodThatCreatesFoo
{
.... realFoo = [[RealFoo alloc] init]; ....
return realFoo;
}
#end
Depending on the goal of your encapsulation, there's also the #private directive:
Access Modifiers