How do i keep my code organised when my app needs a helper class? - iphone

I have a few custom UIViewControllers in my app which need to know the string returned of an NSDate. I could copy and paste the same code between these classes, but that's obviously terrible practise. It's also probably not good to put it in 1 class as a method, then have another class add this class to take advantage of it's method. It seems like a messy thing to do. So what would you recommend i do?
To clarify - I need a method which is given an NSDate and returns a string, for use in several other classes.

Sounds like you either need a function, rather than a method:
//Helpers.h
#import <Foundation/Foundation.h>
NSString * makeAStringFromThisDateSomehow(NSDate * d);
//Helpers.m
#import "Helpers.h"
NSString * makeAStringFromThisDateSomehow(NSDate * d)
{
// Body
// of
// your
// function
}
Or to make a category on NSDate to do what you need:
//NSDate+AndrewsCategory.h
#import <Foundation/Foundation.h>
#interface NSDate(AndrewsCategory)
- (NSString *)Andrew_MakeAStringSomehow;
#end
//NSDate+AndrewsCategory.m
#import "NSDate+AndrewsCategory.h"
#implementation NSDate(AndrewsCategory)
- (NSString *)Andrew_MakeAStringSomehow {
// Body
// of
// your
// method
}
#end
Note the stupid prefix on the method name. That's important to keep your method names from colliding with other method names on framework classes. Usually you would use initials: your company's, yours, or the project's.
In either case, just import the relevant header where you need to use the function or method, and you should be hunky-dory.

I'd consider writing a category on NSDate. Categories let you extend the functionality of existing classes with additional methods without having to mess with the existing implementation of the class. So you can add yourMethod to NSDate, and in the future just be able to call [yourDate yourMethod].
To do this in Xcode, just hit ⌘N to create a new file, and choose Objective-C category, then give it some name and make it a category on NSDate.
Then set up your header:
#interface NSDate (YourCategory)
- (NSString *) yourMethod;
#end
And your implementation:
#implementation NSDate (YourCategory)
- (NSString *) yourMethod {
return [NSString stringWithFormat:#"yourMethod on this date: ", [self description]]; // for example
}
#end
Then just include "NSDate+YourCategory.h" in any file where you want to use yourMethod.

i'd recommend adding the method to a catagory and then adding the header to your projects pch file
#ifdef __OBJC__
#import "yourHeader.h"
#endif
if you google for NSDate+Helper that should give you an idea of the implementation.
Nik

It's probably good to put it in 1 class as a method, then have another class add this class to take advantage of it's method.
simple 1 or 2 methods NSObject subclasses won't make slightest differences in execution

Related

Iphone: Replace functions using reflection

I have a small function which I want to rewrite, so that function is valid for every class.
At the moment I have 10 of the same functions which all work same but every function is for another class.
I know, that I have to do it with reflections, but I am not so sure how to do it.
I already read this link:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
The functions I am talking about are:
-(NSCountedSet *)MissionGetReferecedNested:(id)modelObject
{
setOfObjects = [[NSCountedSet alloc]initWithArray:modelObject.MissionSectionList];
return setOfObjects;
}
-(NSCountedSet *)MissionGetSectionReferecedNested:(id)modelObject
{
setOfObjects = [[NSCountedSet alloc]initWithArray:modelObject.DamageAccountList];
return setOfObjects;
}
MissionSectionList and DamageAccountList are both NSMutableArrays from two different classes.
Is it possible to see if a class consists a NSMutableArray and if yes then it should call the .... modelObject.MyMutableArray?
You can use reflection like this:
- (NSCountedSet *)MissionGet:(id)modelObject
{
SEL propertySelector = NULL;
if ([modelObject respondsToSelector:#selector(MissionSectionList)]) {
propertySelector = #selector(MissionSectionList);
} else if ([modelObject respondsToSelector:#selector(DamageAccountList)]) {
propertySelector = #selector(DamageAccountList);
}
if (!propertySelector) {
[NSException raise:#"Invalid modelObject value" format:#"Model object %# does not contain any recognised selectors", modelObject];
}
return [[NSCountedSet alloc] initWithArray:[modelObject performSelector:propertySelector]];
}
But a more common technique among cocoa programmers would be:
- (NSCountedSet *)MissionGet:(id <MyCustomProtocol>)modelObject
{
return [[NSCountedSet alloc] initWithArray:[modelObject missionArray]];
}
Where you would accept any object which confirms to the protocol MyCustomProtocol. The protocol is defined in a header files somewhere, using:
#protocol MyCustomProtocol
#property (readonly) NSArray *missionArray;
#end
And then in each of your classes, declare it as implementing the protocol:
#interface MissionSectionListClass <MyCustomProtocol>
And add a method implementation:
#implementation MissionSectionListClass <MyCustomProtocol>
- (NSArray *)missionArray
{
return self.MissionSectionList;
}
#end
Using protocols is a bit more code, but it's the "right" way to go. It allows you to add support for new classes, without any change to your MissiongGet... method.
More info about protocols: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProtocols.html
EDIT : Cleared all my answer to this :
I think it's not possible to check if a class has a member variable of specified type. You can only check if a class has a specified method.
So, in this case it will be best if you make all your NSMutableArray list the same name, and then create a declared property for this list, and then do a respondsToSelector in your ...GetReferencedNested method.
So, for example, in all of your class create this property :
#property (nonatomic, retain) NSMutableArray * list;
and then in the ..MissionGetReferencedNested method :
if ([modelObject respondsToSelector:#selector(list)])
...
Correct me if i'm wrong...
In terms of style I'd also follow Abhi's suggestion.
But if you really want to inspect a class that you are stuck with and, for example build a NSCountedSet with the first NSMutableArray variable you can find, you could do it like this:
#import "Utilities.h"
#import <Foundation/Foundation.h>
#import <objc/objc-runtime.h>
#implementation Utilities
+ (NSCountedSet*)initCountedSetWithFirstArrayinObject:(id)someObject {
unsigned int c;
Ivar *ivar_arr = class_copyIvarList([someObject class], &c);
for (unsigned int i = 0; i < c; i++) {
if ([#"#\"NSMutableArray\"" isEqualToString:
[NSString stringWithCString:ivar_getTypeEncoding(ivar_arr[i]) encoding:NSUTF8StringEncoding]
]) {
return [[NSCountedSet alloc] initWithArray:object_getIvar(someObject, ivar_arr[i])];
}
}
return nil;
}
#end
Of course this has very limited real world use because it depends on you knowing that the first array will be the one you're interested in.
I think I have to go with the runtime type editing.(http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html)
The idea with the protocols was good but there I have to change a lot of things in the classes.(which is not possible/allowed) for me. My intension was only to change the functions so that I have only one function for all classes.
I think with the runtime type editing I can check what classes and attributes I have (?) Am I right?
Did somebody already work with runtime type editing?

iPhone: Share a Single Function but Extend Different Classes

Hey is it possible for muliple objects to share a single function but extend different classes? Cause I would rather not have to rewrite my code over and over. Here is an example of what I would do without said method:
I want to have a single, method without having to call [MovieClip loadLandscape]; in the Timeline Implementation
RotatingProtocol.h
#protocol RotatingProtocol
#required
- (void)loadPortrait;
- (void)loadLandscape;
#end
MovieClip.h
#import "RotatingProtocol.h"
#interface MovieClip : UIButton <RotatingProtocol> {
}
#end
MovieClip.m
#import "MovieClip.h"
#implementation MovieClip
- (void)loadPortrait {
// UIButton -> setframe to fit portrait screen
}
- (void)loadLandscape {
// Popup and alert!
}
#end
Timeline.h
#import "RotatingProtocol.h"
#interface Timeline : UIScrollView <RotatingProtocol> {
}
#end
Timeline.m
#import "Timeline.h"
#implementation Timeline
- (void)loadPortrait {
// Do funny animation
}
- (void)loadLandscape {
// Do exactly the same thing as [MovieClip loadLandscape]
}
#end
One possible solution, that I hesitate to recommend, is to provide a category on UIView (the highest level superclass both classes share) that adds the loadLandscape method implementation, then you could leave it out of the objects and just declare the class supports that protocol (and also import the category).
That's kind of extreme since every UIView instance gets the method that could be called, which might confuse something that checks for respondsToSelector instead of conformsToProtocol.
The technique I'd use is to put that implementation into something like a RotatingProtocolImplementation class as a class level method. Something has to know to call the loadLandscape method of your protocol, and that something could just as easily detect the class declared support for the protocol and call the shared class level method instead of a method on the class instance itself - so the protocol could become more of a marker protocol, without as many (or any) methods a class would have to define to support it.

Does calling a protocol method pass program flow control?

I know this is quite possibly a lame question, but I've pulled three consecutive all-nighters and I'm very blurry. And I'm new to Objective C and Cocoa Touch.
I've created a class that provides a delegate method. I'll use simplified example code since the specifics aren't important. The header file looks like this:
#import <Foundation/Foundation.h>
#protocol UsernameCheckerDelegate <NSObject>
#required
- (void)didTheRequestedThing:(BOOL)wasSuccessful;
#end
#interface TheDelegateClass : NSObject {
id <TheDelegateClassDelegate> tdcDelegate;
}
#property (assign) id <TheDelegateClassDelegate> tdcDelegate;
- (void)methodThatDoesSomething:(int)theValue;
#end
And the source file looks like this:
#import "TheDelegateClass.h"
#implementation TheDelegateClass
#synthesize tdcDelegate;
- (void)methodThatDoesSomething:(int)theValue {
if (theValue > 10) {
[[self tdcDelegate] didTheRequestedThing:NO];
// POINT A
}
// POINT B
int newValue = theValue * 10;
NSString *subject = [NSString stringWithFormat:#"Hey Bob, %i", newValue];
// Some more stuff here, send an email or something, whatever
[[self tdcDelegate] didTheRequestedThing:YES];
// POINT C
}
#end
Here's my question: if theValue is in fact greater than 10 and the line above POINT A runs, does program flow control pass out of this method (and back to the didTheRequestedThing delegate method in the object that called this) or does flow continue on through POINT B to POINT C?
I'm hoping for the former because I can simplify the heck out of my code, currently an unpleasant mess of deeply nested ifs and elses.
When the -didTheRequestedThing: method returns, control flow returns back to your POINT A and continues on to POINT B and POINT C. Delegate method calls are exactly like any other method call. If you want to avoid executing the rest of the method after the delegate call, just stick a call to return where your // POINT A comment is.

Set a variable in a different class

I am trying to create an application were 2 classes share a variable. Just to keep the code looking a little bit cleaner I created a 3rd class. This "third class" sole job is to house this variable.
In class 3 I put a "get" and "set" method.
SharedURL.H (Class 3)
#interface SharedURL : NSObject {
NSString *theURL;
}
-(NSString *)getTheURL;
-(void)setTheURL:(NSString *)blah;
#property (readwrite, copy) NSString *theURL;
#end
Implementation:
#import "SharedURL.h"
#implementation SharedURL
#synthesize theURL;
-(NSString *)getTheURL;
{
return theURL;
}
-(void)setTheURL:(NSString *)blah;
{
theURL=blah;
}
#end
In classes 1 and 2:
I Import the class header
I set up the instance variable like so
SharedURL *XMLURL;
I define the property like so
#property (readwrite, assign) SharedURL *XMLURL;
Then in the implementation I set the set method like this
[XMLURL setTheURL:#"http://localhost:8888/xml/MyXMLFile.xml"];
However whenever I implement the fallowing code the getter method returns nil.
NSLog(#" the url is %#", [XMLURL getTheURL]);
How can I get this to actually save the variable that I imput and then return it. I'm looking at some sample code and i cannot find my error it looks to me like I am doing it perfectly fine I think I am overlooking something stupid.
If I understand this right you are calling class 3 from either class 1 or 2 (lets say 1) and set the URL then your go to class 2 and and only ask for the URL, right?
I think your problem is that you are calling something that is independent for each object. I think you can fix this by instead of saying -(NSString *)getTheURL and -(void)setTheURL you need to change it to +(NSString *)getTheURL and +(void)setTheURL (in both the .h and .m files) making it not variable dependent.

Objective-C: How Can I Access String Variable As a Global?

I am new to iPhone development. I want to access a string variable in all the class methods, and I want to access that string globally. How can I do this?
Please help me out.
Leaving aside the issue of global variables and if they are good coding practice...
Create your string outside of any Objective-C class in a .m file in your project:
NSString *myGlobalString = #"foo";
Then put the declaration in a header file that is included by every other file that wants to access your string:
extern NSString *myGlobalString;
OK, well I can't leave it entirely aside. Have you considered putting your "global" string somewhere else, perhaps inside your application delegate as a (possibly read-only) property?
The preferred methods for creating a global variable are:
Create a singleton class that stores
the variables as an attributes.
Create a class that has class methods that return the variables.
Put the class interface in the
universal header so all classes in
the project inherit it.
The big advantage of method (2) is that it is encapsulated and portable. Need to use classes that use the global in another project? Just move the class with the variables along with them.
You can achieve that by implementing getter and setters in the delegate class.
In delegate .h file
Include UIApplication delegate
#interface DevAppDelegate : NSObject <UIApplicationDelegate>
NSString * currentTitle;
- (void) setCurrentTitle:(NSString *) currentTitle;
- (NSString *) getCurrentTitle;
In Delegate implementation class .m
-(void) setCurrentLink:(NSString *) storydata{
currentLink = storydata;
}
-(NSString *) getCurrentLink{
if ( currentLink == nil ) {
currentLink = #"Display StoryLink";
}
return currentLink;
}
So the variable you to assess is set in the currentlink string by setters method and class where you want the string ,just use the getter method.
All the best
I posted an article about my methodology for doing this:
http://www.pushplay.net/2011/02/quick-tip-global-defines/
This is something I primarily use for notification keys. Creating a globals.h file and adding it to the (your_project_name)_Prefix.pch file will ensure it is accessible globally...