I'm working with NSXMLParser that parses a xml document. You have to set the delegate which we would be called every time the parser finds an element. The examples I've looked at all set the delegate to be the same class that's createing:
NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:filename];
[parser setDelegate: self];
Other examples set the delegate to be the parent. What if I want another class (not related to the same class) to handle the delegate. What is the syntax to do so?
I've done this but it doesn't work.
#interface Util : NSObject <NSXMLParserDelegate> {
//Some code here
}
//functions for the delegate and the implementation on the Util.m
//.
//.
//.
Thx for your answers.
I forgot to say that when calling the delegate I assumed that it would be something like this:
[parser setDelegate:Util];
I assumed this knowing that to set the delegate for the same class the message is:
[parser setDelegate:self];
You have to create the Util object first.
The delegate has to be an actual instance of a class :)
Util* util = [[Util alloc] init];
[parser setDelegate:util];
[util release];
Related
Im calling a function in Class B which is in Class A:
ClassA *object = [[ClassA alloc] init];
[object changemethod];
[object release];
In Class A:
-(void)changemethod{
[imageView setImage: [UIImage imageNamed:#"picture.png"]];
NSLog(#"Works");
}
Calling the function in Class A works fine (I get the Logmessage) but the "imageView" is not changing the image. Why? Any clue?
Ok found a solution for my problem. I changed the "changemethod" to a class method. And to access the IBImageView in the class method I put it before the "#implementation". The IBImageView gets added in the "viewDidLoad" method and then changed by calling the classmethod "changemethod". Thanks.
I am from Actionscript Background. In Actionscript Class Method can access only Class Methods and Class properties.
But In Objective C,
How Class method gameResultAll can access Instance Method initFromPlist
+(NSMutableArray *)gameResultAll://Class Method
-(id)initFromPlist:(id)plist;//Instance Method
NSMutableArray *gameResults = [GameResult gameResultAll]; // (returns GameResult array)
Why [self init] method is called instead of [super init] to create an instance from class method.
Thanks in advance.
#import "GameResult.h"
#implementation GameResult
#define GAME_RESULT_KEY #"gameresult_key"
#define SCORE_KEY #"score"
+(NSMutableArray *)gameResultAll
{
NSMutableArray *resultArray = [[NSMutableArray alloc] init];
for (id plist in [[[[NSUserDefaults standardUserDefaults] dictionaryForKey:GAME_RESULT_KEY] mutableCopy] allValues])
{
GameResult *gameResult = [[GameResult alloc] initFromPlist:plist];
[resultArray addObject:gameResult];
}
return resultArray;
}
//Designated initialiser
-(id)initFromPlist:(id)plist
{
self = [self init];
if(self)
{
if([plist isKindOfClass:[NSDictionary class]])
{
NSDictionary *resultDictionary = (NSDictionary*)plist;
_score = (int)resultDictionary[SCORE_KEY];
}
}
return self;
}
You asked:
How Class method gameResultAll can access Instance Method initFromPlist
It can access that method because you used the alloc method, which creates an instance of GameResult. Now that you have an instance, you can use instance methods in conjunction with this instance.
By the way, this is a very common pattern, a "convenience" class method that allocates an instance of an object (with alloc) and initializes the object (with init or some permutation of that). Or, as in this case, it can create an array of these objects.
You then go on to ask:
Why [self init] method is called instead of [super init] to create an instance from class method.
I can understand the confusion, but there is an important, yet subtle distinction in the behavior of these two.
Imagine this scenario:
At some future date, you subclass GameResult, e.g. ArcadeGameResult;
You implemented an init method for ArcadeGameResult that initializes some properties unique to this subclass; and
You happen to initialize a ArcadeGameResult instance like so:
ArcadeGameResult *agr = [[ArcadeGameResult alloc] initFromPlist:plist];
Because the initFromPlist uses [self init], it means that the the initFromPlist method of GameResult will end up calling the init method of the object (which in this example, is actually a ArcadeGameResult object). But if initFromPlist in GameResult called [super init] instead, it would not have called ArcadeGameResult's init method and thus initFromPlist would be problematic if ever used in conjunction with a subclass.
Bottom line, unless the method you're calling is the exact same method signature, it's safer to call the self rendition rather than the super rendition. It's a little more flexible in case you ever decide to subclass in the future.
There is a corollary to the counsel. When calling class methods from an instance method, you should refer to [self class] rather than the class name. So, imagine your GameResult class had a class method:
+ (void)someClassMethod
{
// do something
}
If you had some GameResult instance method that was going to avail itself of this method, you might be tempted to write:
- (void)someInstanceMethod
{
// do some stuff
[GameResult someClassMethod];
}
But that's not a good idea. You would instead use the following:
- (void)someInstanceMethod
{
// do some stuff
[[self class] someClassMethod];
}
They look very similar, but the latter lets you implement a someClassMethod in a subclass, and this instance method will still work. If you use the former construct, the subclassed class method wouldn't be called by someInstanceMethod.
These are subtle issues, and probably not critical for your current code sample. But hopefully it illuminates the choice of [self init] versus [super init] in this situation.
In Actionscript Class Method can access only Class Methods and Class properties.
That's not different in Objective-C either (because nothing else would make sense), so:
How Class method GameResultAll can access Instance Method initFromPlist
Only through a valid instance.
Why [self init] method is called instead of [self super] to create an instance from class method.
Because the latter is a syntax error, perhaps? Read a basic Objective-C tutorial.
I'm working on an subclass of NSURLConnection. I added some properties and functionality. I implemented the NSURLConnectionDelegate and it's methods.
Now I need to pass the NSURLConnection (and it's properties) to my subclasses delegate. I implemented a delegate protocol for this.
Here is an code example:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if([_delegate respondsToSelector:_didReceiveDataSelector]) {
[_delegate performSelector:_didReceiveDataSelector withObject:connection];
}
Now I also need to return my subclasses properties. I tried to simply cast the instance:
mySubClass *obj = (mySubClass *)connection;
obj.userInfo = self.userInfo;
But it turned out (NSLog(#"%#", NSStringFromClass([obj class]));) that the cast returns an object which's class is still NSURLConnection.
Now I wonder how to merge all property values of the superclass instance and my subclasses properties.
Thanks for help!
Casting doesn't change an object's class. Casting just tells the compiler "This object is actually a whatever". It's for when the compiler is misunderstanding what class something is.
Given that casting doesn't seem to be working for you, then it means you're not being passed an instance of your custom subclass. So you should be looking at the code where you create the connection in the first place. I'd expect to see something like:
mySubClass *conn = [[mySubClass alloc] initWithRequest:req delegate:self];
Is that what your code looks like? If not (i.e. if you create an NSURLConnection rather than a mySubClass), switch to creating a mySubClass.
I solved the problem.
Now I'm doing this:
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate {
self = [super initWithRequest:request delegate:self];
if(self) {
_delegate = delegate;
}
}
This way I'm able to receive the delegate methods on my subclass, extend the informations in the method and end the custom selectors to the delegate.
In the viewControllers I can do something like this:
mySubClass *con = [[mySubClass alloc] initWithRequest:req delegate:self];
[con setDidReceiveResponseSelector:#selector(connection:didGetResponse)];
[con start];
So I can have like ten URLRequests within the same viewController with different delegate methods for the same action.
I'm quite a newbie in Objective C, though I have some background in Java reflection.
Here, I have a classic class method findAll that find all the domain objects from the database. The class Univers directly inherits from DomainObject
#interface DomainObject : NSObject
- (NSString *) execute : (NSString*) method withJson:(NSString*)json;
+ (NSString*)findAll: (NSString*)json;
#end
#implementation DomainObject
- (NSString *) execute: (NSString*) method withJson:(NSString*)json{
method = [NSString stringWithFormat:#"%#%#", method, #":"];
//method is 'findAll:'
NSString* result = [ self performSelector:
NSSelectorFromString(method) withObject:json];// Error here
return result;
}
#end
The code was working when findAll was NOT a class method (ie -findAll declaration), but now I have the error : NSInvalidArgumentException -[Univers findAll:]
It clearly seems that the runtime is looking for an instance method.
Any idea to find my class method ?
Instead of calling
NSString* result = [self performSelector:NSSelectorFromString(method) withObject:json];
you need to call
NSString* result = [[self class] performSelector:NSSelectorFromString(method) withObject:json];
for class methods.
After all it's the object instance's class that supposed to be calling the method, not the instance itself.
Short explanation: NSObject implements - (Class)class; (not to be mistaken with + (Class)class of similar effect, which NSObject implements, too!) which returns the Class object of your instance object. Keep in mind that in Objective-C in addition to plain instance objects, Classes are actual objects, too: objects of type Class, that is (vs. id, NSObject, …).
See the documentation for the -class method here.
Btw, you should probably wrap your method call into an conditional block to prevent exceptions caused by calls to missing methods.
SEL selector = NSSelectorFromString(method);
if ([[self class] respondsToSelector:selector]) {
NSString* result = [[self class] performSelector:selector withObject:json];
}
In general it's a common pattern in Objective-C to call an object's class method by receiving the class object via [object class].
Consider this case of a class called Foo implementing a convenience method for returning an autporeleased instance of itself (to be called via: Foo *newFoo = [Foo foo];):
While it would certainly be possible to implement said method like this (after all we know the object's class name, right?):
+ (id)foo {
return [[[Foo alloc] init] autorelease];
}
the correct way is this:
+ (id)foo {
return [[[self alloc] init] autorelease];
}
As the first one would cause problems with polymorphism in subclasses (Such as a subclass called FooBar, for which it should clearly be [FooBar alloc] …, not [Foo alloc] …. Luckily [[self class] alloc] solves this dynamically).
While this is clearly not the right place for a thorough explanation of this (rather offtopic one might say) it's certainly worth noting/warning about, imho.
Normally I don't have any problem adding a setter method to a class.
However, I'm trying to add to library usage class, which must be causing the problem.
Heres the class I've added it to...
#interface GraphController : TKGraphController {
UIActivityIndicatorView *indicator;
NSMutableArray *data; //I've added
NSString *strChartType; //I've added
}
-(void)setContentType:(NSString*)value; //I've added
#end
#implementation GraphController
-(void)setContentType:(NSString*)value { //I've added
if (value != strChartType) {
[value retain];
[strChartType release];
strChartType = value;
NSLog(#"ChartType=%#", strChartType);
}
}
Heres where I'm getting a warning..
UIViewController *vc = [[GraphController alloc] init];
[vc setContentType:myGraphType]; //Warnings on this line see below
[self presentModalViewController:vc animated:NO];
[vc release];
myGraphType if defined in my constant class.
* Warnings *
warning: 'UIViewController' may not respond to '-setContentType:'
warning: (Messages without a matching method signature
I know the first warning appears when you haven't added the method to the implementation. but I have.
Where am I going wrong ?
UIViewController *vc = [[GraphController alloc] init];
means that vc points to an instance of GraphController but the variable itself is of type UIViewController *, and UIViewController doesn’t declare a -setContentType: method.
Replace that with
GraphController *vc = [[GraphController alloc] init];
to tell the compiler you’re working with a GraphController instance, and it will recognise your -setContentType: method.
You just have to let the compiler know that you're working with a class that it knows responds to the method. You can do it a couple of ways but the easiest one if you just want to eliminate the warning is to cast the object in line before you make the method call.
UIViewController *vc = [[GraphController alloc] init];
[(GraphController *)vc setContentType:myGraphType]; //No warning should appear now.
[self presentModalViewController:vc animated:NO];
[vc release];