Objective-C forwardInvocation: - objective-c

I often do something like:
CoolViewController *coolViewController = [[CoolViewController alloc] init];
[self.navigationController pushViewController:coolViewController animated:YES];
[coolViewController release];
How would I, in a category of UINavigationController, override forwardInvocation: so that I could just instead do:
[self.navigationController pushCoolViewControllerAnimated:YES];
Please include the relevant code in your answer, not just an explanation. Thank you!
Feel free to comment on whether this is good practice. I'm also asking this for educational purposes, but it seems to me that in this case, the simplification in code may outweight the unnoticeable (correct?) cost in processing time & memory usage. Also, I come from a Ruby background and love to use dynamic programming to simplify things, e.g., dynamic finders (e.g., find_by_name) in Rails.
Bonus points if you could implement pushCoolViewControllerAnimated:withBlock and invoke the block after initializing the view controller, allowing me to set certain instance variables on the view controller created.
UPDATE: I just remembered that ARC is coming soon. So this specific example may not be so helpful then, but still a great exercise/example that could be used in other cases, e.g., dynamic finders for Core Data & passing a block to configure the NSFetchRequest.

Use the dynamic method resolution mechanism described in the Objective-C Runtime Programming Guide, specifically, +[NSObject resolveInstanceMethod:]:
#implementation UINavigationController (FWD)
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
NSString *name = NSStringFromSelector(sel);
NSString *prefix = #"push";
NSString *suffix = #"Animated:";
if ([name hasPrefix:prefix] && [name hasSuffix:suffix]) {
NSRange classNameRange = {[prefix length],
[name length] - [prefix length] - [suffix length]}
NSString *className = [name substringWithRange:classNameRange];
Class cls = NSClassFromString(className);
if (cls) {
IMP imp = imp_implementationWithBlock(
^(id me, BOOL animated) {
id vc = [[cls alloc] init];
[me pushViewController:vc animated:animated];
[vc release];
});
class_addMethod(cls, sel, imp, "v#:c");
return YES;
}
}
return [super resolveInstanceMethod:sel];
}
#end
Of course, if UINavigationController already uses +resolveInstanceMethod:, you've now broken it. Doing this in a subclass of UINavigationController, or using method swizzling to enable invoking the original implementation, would solve that problem.
The version accepting a post-creation block is a straightforward extension (change the block parameters, change the type encoding, change the selector name pattern and how you extract the intended class name).

Related

My NSString is determined to equal null, infuriating

This has been bugging me all night, It doesn't make any sense. This function returns whatever it's supposed to. EG, the issueName.
-(id)initWithIssue:(NSString *)string {
self = [super initWithNibName:nil bundle:nil];
if (self) {
NSString *thing = string;
issueName = [[NSString alloc]initWithString:thing];
NSLog(#"The issue name = %#", issueName);
}
return self;
}
However if I try to access 'issueName' in the viewDidLoad: nothing, it's equal to null no matter what I do. I've tried cleaning, setting a custom setter, switching between a property or a Ivar... ect. What's so infuriating is that this string just disappears at this point in the programe.
What the hell is going on, this is infuriating.
Edit
This the the entire code that is relevant. And how I started off.
Dot h file:
#interface BFPaidAreaViewController : UITabBarController <BFNewsTableViewControllerDelegate> {
NSString *issueName;
}
-(id)initWithIssue:(NSString *)string;
Dot m file:
-(id)initWithIssue:(NSString *)string {
self = [super init];
if (self) {
// PLPiper I had it that way before, because I was fiddling out of frustration
issueName = [[NSString alloc] initWithString:string];
NSLog(#"This is Called, the issue name is equal to = %#", issueName);
}
return self;
}
-(void)viewDidLoad {
[super viewDidLoad];
NSLog(#"The issue = %#", issueName);
}
I'm calling the view controller like so:
BFPaidAreaViewController *pavc = [[BFPaidAreaViewController alloc]initWithIssue:#"test"];
This will log:
This is Called, the issue name is equal to = test
The issue = (null)
New Edit
Found the problem. It's a UITableViewController. Strange, when I change it's class to a UIViewController it works. Is this a bug or just normal behaviour? But more pressing, how to I get round this limitation?
(Just to explain what I've done UI wise, the UITabBarController is in a modal View. This works fine with a UIViewController.)
God Awful Fix
-(id)initWithIssue:(NSString *)string {
self = [super initWithNibName:nil bundle:nil];
if (self) {
NSString *thing = string;
issueName = [[NSString alloc]initWithString:thing];
NSLog(#"The issue name = %#", issueName);
}
[self viewDidLoad];
return self;
}
Makes me feel dirty. But it will have to do for now, I can continue. If anyone can think of a solution please tell. Sorry about my feistiness, it was incredibly frustrating listening to people say, 'what the hell is this?? what is issueName?? an ivar??' when it was really implicit in the question.
Okay, first of all, replace:
self = [super initWithNibName:nil bundle:nil]; // Unneeded nil arguments
with:
self = [super init]; // Equivalent method, less processing involved.
Secondly, replace:
NSString *thing = string;
issueName = [[NSString alloc]initWithString:thing];
with just:
_issueName = [[NSString alloc] initWithString:string];
If issueName is a property (and you haven't #sythesized it to anything else) its representation should be _issueName.
The above fixes are more or less just make the code more succinct. The issue is probably with the code in viewDidLoad: (See below).
Now you can initialise your Issue object, and use the following code to display the issue name:
// Init:
Issue *myIssue = [[Issue alloc] initWithIssue:#"Example Issue"];
// Log:
NSLog(#"%#", myIssue.issueName);
And the log should show:
Example Issue
can you try this:
make the issueName a property, like
#property (strong, nonatomic) NSString *issueName;
then use it like this,
-(id)initWithIssue:(NSString *)string {
self = [super initWithNibName:nil bundle:nil];
if (self) {
NSLog(#"The string = %#", string);
self.issueName = string;
NSLog(#"The issue name = %#", issueName);
}
return self;
}
if you are using the automated synthetized property (i.e not declaring the #synthentize manually for the issueName), then your iVar will be called _issueName instead of issueName
what do you get from the above code ?
I find this somewhat curious. You call [super initWithNibName:nil bundle:nil]. This leads me to believe that this might be a subclass of NSViewController. If you init an NSViewController like this, barring some other, pretty non-standard stuff, -viewDidLoad probably won't get called because there's no NIB to be loaded (because you passed nil to super). But clearly you're setting a breakpoint in -viewDidLoad so it's getting called (on something). This makes me think that you have this class specified in a XIB somewhere as a File's Owner or as a NIB-loaded custom object. If that's the case, it leads me to believe that the instance you're init-ing and the instance on which -viewDidLoad is being called aren't the same instance. You can confirm this for yourself by putting NSLog(#"self: %p", self); in each method and seeing whether they are the same or different.
If the instance that is getting a call to -viewDidLoad is NIB-loaded, then your init method won't be called. Instead it will use -initWithCoder
If you can elaborate on the situation here (i.e. how this is getting instantiated, are there any XIBs involved, etc), I will edit my answer to provide more help, but I don't think there's enough information here to be truly helpful.
I feel your frustration. Assuming standard behavior, any of the suggestions here should have worked. This only reinforces my suspicion that these are not the same instance (between -initWithIssue and -viewDidLoad.

Saving an NSArray of custom objects

I've created a subclass of UIImage (UIImageExtra) as I want to include extra properties and methods.
I have an array that contains instances of this custom class.However when I save the array, it appears the extra data in the UIImageExtra class is not saved.
UIImageExtra conforms to NSCoding, but neither initWithCoder or encodeWithCoder are called, as NSLog statements I've added aren't printed.
My method to save the array looks like this:
- (void)saveIllustrations {
if (_illustrations == nil) {
NSLog(#"Nil array");
return;
}
[self createDataPath];
//Serialize the data and write to disk
NSString *illustrationsArrayPath = [_docPath stringByAppendingPathComponent:kIllustrationsFile];
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:_illustrations forKey:kIllustrationDataKey];
[archiver finishEncoding];
[data writeToFile:illustrationsArrayPath atomically: YES];
}
And the UIImageExtra has the following delegate methods for saving:
#pragma mark - NSCoding
- (void)encodeWithCoder:(NSCoder *)aCoder {
NSLog(#"Encoding origin data!");
[super encodeWithCoder:aCoder];
[aCoder encodeObject:originData forKey:kOriginData];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:(NSCoder *) aDecoder]) {
NSLog(#"Decoding origin data");
self.originData = [aDecoder decodeObjectForKey:kOriginData];
}
return self;
}
My code to create the array in the first place looks like this (in case that offers any clues)
for (NSDictionary *illustrationDict in illustrationDicts) {
NSString *illustrationString = [illustrationDict objectForKey:#"Filename"];
NSNumber *xCoord = [illustrationDict objectForKey:#"xCoord"];
NSNumber *yCoord = [illustrationDict objectForKey:#"yCoord"];
UIImageExtra *illustration = (UIImageExtra *)[UIImage imageNamed:illustrationString];
//Scale the illustration to size it for different devices
UIImageExtra *scaledIllustration = [illustration adjustForResolution];
NSValue *originData = [NSValue valueWithCGPoint:CGPointMake([xCoord intValue], [yCoord intValue])];
[scaledIllustration setOriginData:originData];
[self.illustrations addObject:scaledIllustration];
}
Or am I just going about saving this data the wrong way? Many thanks.
Your code to initialize the array is not actually creating instances of your UIImageExtra subclass.
UIImageExtra *illustration = (UIImageExtra *)[UIImage imageNamed:illustrationString];
returns a UIImage. Casting it doesn't do what you were intending.
UIImageExtra *scaledIllustration = [illustration adjustForResolution];
is still just a UIImage.
One straightforward-but-verbose way to approach this would be to make UIImageExtra a wrapper around UIImage. The wrapper would have a class method for initializing from a UIImage:
+ (UIImageExtra)imageExtraWithUIImage:(UIImage *)image;
And then every UIImage method you want to call would have to forward to the wrapped UIImage instance-- also being careful to re-wrap the result of e.g. -adjustForResolution lest you again end up with an unwrapped UIImage instance.
A more Objective-C sophisticated approach would be to add the functionality you want in a Category on UIImage, and then use method swizzling to replace the NSCoding methods with your category implementations. The tricky part of this (apart from the required Objective-C runtime gymnastics) is where to store your "extra" data, since you can't add instance variables in a category. [The standard answer is to have a look-aside dictionary keyed by some suitable representation of the UIImage instance (like an NSValue containing its pointer value), but as you can imagine the bookkeeping can get complicated fast.]
Stepping back for a moment, my advice to a new Cocoa programmer would be: "Think of a simpler way. If what you are trying to do is this complicated, try something else." For example, write a simple ImageValue class that has an -image method and an -extraInfo method (and implements NSCoding, etc.), and store instances of that in your array.
You can't add objects to an NSArray after init. Use NSMutableArray, that might be the issue.

Adding a searchBar to your TableView

I'd like to add search functionality to a TableView in my app. I populate a table with an NSArray which has x amount of Objects that contain 3 NSStrings. Here's how I construct that NSArray:
First I create a class Code.h:
#import <Foundation/Foundation.h>
#interface Code : NSObject
#property (nonatomic, strong) NSString *codeName;
#property (nonatomic, strong) NSString *codeNumber;
#property (nonatomic, strong) NSString *codeDesc;
#end
Next, I synthesize these NSStrings in Code.m.
Now in my SearchViewController.m, Here's how I create my dataset:
NSMutableArray *codes;
codes = [[NSMutableArray alloc] init];
Code *c = [[Code alloc] init];
[c setCodeNumber:#"1"];
[c setCodeName:#"First Title Here"];
[c setCodeDesc:#"I might write a desc in here."];
[codes addObject:c];
c = [[Code alloc] init];
[c setCodeNumber:#"2"];
[c setCodeName:#"Second Title Here"];
[c setCodeDesc:#"2nd desc would be written here."];
[codes addObject:c];
and so on...
Here is how I display it: cellForRowAtIndexPath:
Code *c = [codes objectAtIndex:indexPath.row];
NSString *fused = [NSString stringWithFormat:#"%# - %#",[c codeNumber],[c codeName]];
cell.textLabel.text = fused;
return cell;
So now that you know how my data is structured and displayed, do you have an idea of how to search either the NSArray or possibly (preferably) the TableCells that have already been created?
I have been through the few tutorials online regarding Adding a Search Bar to a TableView, but all of them are written for using arrays setup using simple arrayWithObjects.
SIDETHOUGHT: Is it possible for me to construct an arrayWithObjects:#"aaa-1",#"bbb-2",#"ccc-3"... from my data? If i can manage that, I can use those tutorials to populate my cells and search them!
UPDATE:
Your second answer makes plenty more sense to me! Thanks for that. I beleive I have followed your instruction, but I am getting a "-[Code search:]: unrecognized selector sent to instance 0x6a2eb20` when that line is hit.
I added #property (nonatomic, strong) NSString *searchString; to Code.h and synthesized it in Code.m
I added NSMutableSet *searchResults; to SearchViewController.h's #interface
I added your methods performSearchWithString and matchFound to SearchViewController.m
Directly under those I added this to call performSearchWithString
x
- (void)searchBar:(UISearchBar *)theSearchBar textDidChange:(NSString *)searchString {
NSLog(#"%#",searchString); //Just making sure searchString is set
[self performSearchWithString:searchString];
[self.tableView reloadData];
}
The error hits when [codes makeObjectsPerformSelector:#selector(search:) withObject:self]; runs. I am confused b/c it sounds like Code doesn't recognize searchString, but I know I added it in Code.h.
UPDATE:
In order to store objects in searchResults, I had to change searchResults from a NSMutableSet to a NSMutableArray and modify - (void)matchFound:(Code *) matchingCode {} to this:
-(void) matchFound:(Code *) matchingCode {
Code *match = [[Code alloc] init];
if (searchResults.count == 0) {
searchResults = [[NSMutableArray alloc] init];
[match setCodeName:[matchingCode codeName]];
[match setCodeNumber:[matchingCode codeNumber]];
[match setCodeDesc:[matchingCode codeDesc]];
[searchResults addObject:match];
}
else
{
match = [[Code alloc] init];
[match setCodeName:[matchingCode codeName]];
[match setCodeNumber:[matchingCode codeNumber]];
[match setCodeDesc:[matchingCode codeDesc]];
[searchResults addObject:match];
}
With a few other tweeks, I've got a working searchbar for my tableView. Thanks Tim Kemp!
Oh, also case insensitive search was what I was looking for. NSRange rangeName = [codeName rangeOfString: searchString options:NSCaseInsensitiveSearch];
I hope this question and answer will be helpful to the next developer learning objective-c with this question!
Simpler approach
You asked for a simpler solution. This one isn't nearly as flexible, but it will achieve the same things as my earlier answer for this specific case.
Once again we are going to ask Code to search its strings for us. This time, we are going to skip the SearchRequest and the block callback and implement it directly.
In your SearchViewController you will create two methods. One to do the search, and one callback to process any results as they come back. You will also need a container to store matching Code objects (more than one might match, presumably.) You will also need to add a method to Code to tell it what the search string is.
Add an ivar NSMutableSet called searchResults to SearchViewController.
Add a property of type NSString * called searchString to Code
Add the search method to SearchViewController. This is what you'll call when you want to initiate a search across all your codes:
-(void) performSearchWithString:(NSString *) searchString {
// Tell each Code what string to search for
[codes makeObjectsPerformSelector:#selector(setSearchString:) withObject:searchString];
// Make each code perform the search
[codes makeObjectsPerformSelector:#selector(search:) withObject:self];
}
Then you will also need a callback in SearchViewController. This is so that your Code objects can tell the SearchViewController that they have found a match:
-(void) matchFound:(Code *) matchingCode {
[searchResults addObject:matchingCode];
// do something with the matching code. Add it to a different table
// view, or filter it or whatever you need it to do.
}
However do note that you don't have to use the searchResults mutable set; you may well want to just call another method to immediately add the returned result to some other list on screen. It depends on your app's needs.
In Code, add a search method a bit like we had before, but instead of the SearchRequest parameter we'll pass in a reference to the SearchViewController:
- (void) search:(SearchViewController *) searchVC {
// Search each string in turn
NSRange rangeNum = [codeNumber rangeOfString : searchString];
NSRange rangeName = [codeName rangeOfString : searchString];
NSRange rangeDesc = [codeDesc rangeOfString: searchString];
if (rangeNum.location != NSNotFound || rangeName.location != NSNotFound || rangeDesc.location != NSNotFound) {
[searchVC matchFound:self];
}
}
Do you see how that works? If there's a match in any of the strings (|| means 'or') then pass self (which means exactly what it sounds like: the current object that's running this code right now) back to a method in the view controller called searchVC. This is called a callback because we are "calling back" to the object which originally sent us the message to do the search. We have to use callbacks rather than simple return types because we have used makeObjectsPerformSelector to tell every single Code in the codes array to do a search. We never explicitly called the search method ourselves, so we have no way to capture the return value from each search. That's why its return type is void.
You can extend matchFound to take an additional parameter which identifies which string the match was in (i.e. çodeNumber, codeName or codeDesc.) Look into enums as one good approach to pass around that kind of data.
Hope that's bit simpler.
Here is a link to an excellent language introduction/tutorial which will eliminate much confusion.
EDIT In your last comment you said that searchResults was null. I said to add it as an ivar somewhere in SearchViewController. In your initialiser method for SearchViewController you should call
searchResults = [[NSMutableSet alloc] initWithCapacity:50]` // Choose some sensible number other than 50; enough to hold the likely number of matching Code objects.
Alternatively you could 'lazy initialise' it in matchFound:
- (void) matchFound:(Code *) matchingCode {
if (!searchResults)
searchResults = [[NSMutableSet alloc] initWithCapacity:50];
[searchResults addObject:matchingCode];
}
Though if you do this you should be aware that anywhere else you access searchResults may find that it's null if matchCode: has never previously been called.
Original, flexible and more complicated answer
I'm a little unclear as to what you're trying to do, so I'm going with your title, "Searching each string in each object of an array." In your case, your Codes have three strings and your array has multiple Codes. I assume that you need a way to tell the caller - the code that wants to do the search - which Code matches.
Here is one approach. There are easier ways but this technique is quite flexible. Broadly, we are going to make the Code object do the work of searching its own strings. We are then going to give the Code object the ability to tell the caller (i.e. the object that owns the codes array, presumably your table view controller) whether any of its strings match the search string. We will then use NSArray's method makeObjectsPerformSelector to have to tell all of its Code objects to search themselves. We will use a block for a callback.
Firstly, add a search method to Code (in the interface, or as a category depending on your design), something like this:
-(void) search:(SearchRequest *) request {
// Search using your favourite algorithm
// eg bool matches = [searchMe [request searchString]];
if (matches) {
[request foundMatch:self];
}
}
SearchRequest is new. It's a place to tie together a search string and a callback block. It looks something like this:
#interface SearchRequest
#property (retain) NSString * searchString;
#property (copy) void (^callback)(Code *);
- (id) initWithSearchString:(NSString *) search callback:(void (^)(Code *)) callback;
- (void) foundMatch:(Code *) matchingCode;
#end
#implementation SearchRequest
// synthesize...
// initialiser sets ivars
- (void) foundMatch:(Code *) matchingCode {
callback(matchingCode);
}
The callback block is our way of communicating back to the caller.
When you want to perform a search, construct a SeachRequest object with the string you're searching for and a block which contains the method to call when you get a match.
That would look like this, in the caller:
- (void) performASearchWithString:(NSString *) searchForMe {
SearchRequest * req = [[SearchRequest alloc] initWithSearchString:searchForMe
callback:^(Code * matchingCode) {
[self foundAHit:matchingCode];
}];
[codes makeObjectsPerformSelector:#selector(search:) withObject:req];
}
You then need to implement foundAHit in your caller, which takes the matching Code and does something with it. (You don't have to use a block: you could store a reference to the caller and a selector to call on it instead. I won't go into the arguments for either case here. Other answerers can propose alternatives.)

NSMutableDictionary Singleton issue

I am coding Objective-C using the Cocos2D framework, and I have a singleton used for multiple purposes. One new purposes is to get and set character's "states" which are strings. I've recently made an NSDictionary for this purpose, but I have issues with the program freezing up when a method inside the singleton is called.
Here's the singleton code. I'm just leaving in the character state stuff:
.h
#interface ExGlobal : NSObject {
NSArray *charStates_keys;
NSArray *charStates_objects;
NSMutableDictionary *charStates;
}
#property(nonatomic, retain) NSMutableDictionary *charStates;
+(ExGlobal*)sharedSingleton;
- (NSString *)charState:(NSString *)charName;
- (void)set_charState:(NSString *)value forCharName:(NSString *)charName;
#end
.m
#import "ExGlobal.h"
#implementation ExGlobal
#synthesize charStates;
static ExGlobal* _sharedSingleton = nil;
+(ExGlobal*)sharedSingleton {
#synchronized([ExGlobal class]) {
if (!_sharedSingleton) {
[[self alloc] init];
}
return _sharedSingleton;
}
return nil;
}
+(id)alloc {
#synchronized([ExGlobal class]) {
NSAssert(_sharedSingleton == nil, #"Attempted to allocate a second instance of a singleton.");
_sharedSingleton = [super alloc];
return _sharedSingleton;
}
return nil;
}
-(id)init {
self = [super init];
if (self != nil) {
// initialize stuff here
exitName = #"ruinsSkyMid";
sceneChangeKind = #"reborn";
charStates = [[NSMutableDictionary alloc] init];
charStates_keys = [NSArray arrayWithObjects:#"Feathers", #"Hummus", nil];
charStates_objects = [NSArray arrayWithObjects:#"at wall", #"with Feathers", nil];
charStates = [NSMutableDictionary dictionaryWithObjects:charStates_objects forKeys:charStates_keys];
}
return self;
}
- (NSString *)charState:(NSString *)charName{
NSString *value = [charStates objectForKey:charName];
return value;
}
- (void)set_charState:(NSString *)charState forCharName:(NSString *)charName{
[charStates setObject:charState forKey:charName];
}
- (void)dealloc {
//I know it doesn't get called, but just in case
[charStates release];
[super dealloc];
}
#end
It's unclear to me what exactly the issue is when it freezes. When this happens, all I get in the console is:
Program received signal: “EXC_BAD_ACCESS”.
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.3.5 (8L1)/Symbols/Developer/usr/lib/libXcodeDebuggerSupport.dylib (file not found).
Previous frame inner to this frame (gdb could not unwind past this frame)
Previous frame inner to this frame (gdb could not unwind past this frame)
Which I'm sure doesn't help finding the issue. I found if I redefine charStates_keys, charStates_objects and charStates inside both the charState and set_charState methods, it seems to work without freezing, except set_charState does not change the state.
It isn't freezing, it is crashing. Hence the EXC_BAD_ACCESS. It looks like your Xcode installation is borked, too, as the two messages following should not happen.
Note that methods should not have _s in the name; not a cause of the problem, but a comment on following convention.
You aren't retaining charStates and that is likely the cause of the crash.
Not an answer as such but I didn't have enough space in the comments field above to post this, but it might be useful.
As bbum already said, your lack of retaining charStates is likely the problem.
If you are confused about when to retain and not retain objects there's a really good book called "Learn Objective-C on the Mac" and I know it's a Mac book but most of it applies to iPhone too. On page 171 of chapter 9 (Memory Management) it talks about the "Memory Management Rules" and how if you are confused about when to retain or not then you don't understand the simple rules of Objective C memory management.
Essentially if you create an object using new, alloc or copy, then the retain count is automatically set to 1 so the object is retained and does not require you to retain it and will require a subsequent release to deallocate.
If you create the object any other way then the object will be an autoreleased object.
Obviously these rules only apply within the standard iOS libraries and can't necessarily be applied to third party libraries.
I recommend anyone who doesn't fully understand memory management in Objective C read this book. I found highly enlightening even for my iPhone work.
Hope that helps/.

Will this work?

UILabel *testLbl = [[self alloc] init];
This is where the confusion started:
It’s usually better to use a variable other than self to refer to an instance inside a class
method:
+ (id)rectangleOfColor:(NSColor *)color {
id newInstance = [[Rectangle alloc] init]; // GOOD [newInstance setColor:color]; return [newInstance autorelease];
}
In fact, rather than sending the alloc message to the class in a class method, it’s often better to send alloc to self. This way, if the class is subclassed, and the rectangleOfColor: message is received by a subclass, the instance returned will be the same type as the subclass (for example, the array method of NSArray is inherited by NSMutableArray).
+ (id)rectangleOfColor:(NSColor *)color {
id newInstance = [[self alloc] init]; // EXCELLENT [newInstance setColor:color]; return [newInstance autorelease];
}
No, It'll cause a "UILable undeclared (first use in this function)" error.
No, it won't work. In your first line, you are sending the alloc message to an instance of a class. In the examples you copied out of Apple's documentation, they are sending alloc messages to the Class Rectangle. The difference is that your line is (apparently) inside an instance method, Apple's examples are inside class methods. There is a difference.
Like #Denis mentioned, you can do what you're trying to do by saying [[[self class] alloc] init], but in practice, don't do this. You'll almost never need the flexibility this offers and it will only muddy the intent of the new object.