Showing posts with label Cocoa. Show all posts
Showing posts with label Cocoa. Show all posts

Thursday, September 17, 2009

Assigning pointer to pointer in Objective-C

Pointer variable is a variable itself, so it has an address. So &str1 results in the address of the pointer variable, and str1 is an expression that results in whatever the pointer variable is holding - the address of the object it's pointing to.

Assume that:

  • the object holding the NSString "one" is at address 0x00000100
  • the object holding the NSString "two" is at address 0x00000200

Then your pointers might look something like this:

At initialization:

str1
0xbfffd3c8 +---------------+
| |
| 0x00000100 |
| ("one") |
+---------------+

str2
0xbfffd3cc +---------------+
| |
| 0x00000200 |
| ("two") |
+---------------+

=======================================

After the str1 = str2; assignment:

str1
0xbfffd3c8 +---------------+
| |
| 0x00000200 |
| ("two") |
+---------------+

str2
0xbfffd3cc +---------------+
| |
| 0x00000200 |
| ("two") |
+---------------+

Дополнительная ссылка:
stackoverflow.com/questions/529482/objective-c-pointers

Static variables in Objective-C

// MyClass.h
@interface
MyClass : NSObject {
}
+ (NSString*)str;
+ (void)setStr:(NSString*)newStr;
@end

// MyClass.m
#import "MyClass.h"

static NSString* str;

@implementation
MyClass

+ (NSString*)str {
return str;
}

+ (void)setStr:(NSString*)newStr {
if (str != newStr) {
[str release];
str
= [newStr copy];
}
}
@end

Дополнительная ссылка на обсуждение:
http://discussions.apple.com/thread.jspa?threadID=1592519

Чтобы сделать доступным эту переменную за пределами m файла,
следует объявить переменную как extern:
http://www.omnigroup.com/mailman/archive/macosx-dev/2002-April/037869.html

Singleton in Objective-C

Mac recommendations to create singlton:

static MyGizmoClass *sharedGizmoManager = nil;

+ (MyGizmoClass*)sharedManager
{
@synchronized(self) {
if (sharedGizmoManager == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedGizmoManager;
}

+ (id)allocWithZone:(NSZone *)zone
{
@synchronized(self) {
if (sharedGizmoManager == nil) {
sharedGizmoManager = [super allocWithZone:zone];
return sharedGizmoManager; // assignment and return on first allocation
}
}
return nil; //on subsequent allocation attempts return nil
}

- (id)copyWithZone:(NSZone *)zone
{
return self;
}

- (id)retain
{
return self;
}

- (unsigned)retainCount
{
return UINT_MAX; //denotes an object that cannot be released
}

- (void)release
{
//do nothing
}

- (id)autorelease
{
return self;
}



#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
\
static classname *shared##classname = nil; \
\
+ (classname *)shared##classname \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [[self alloc] init]; \
} \
} \
\
return shared##classname; \
} \
\
+ (id)allocWithZone:(NSZone *)zone \
{ \
@synchronized(self) \
{ \
if (shared##classname == nil) \
{ \
shared##classname = [super allocWithZone:zone]; \
return shared##classname; \
} \
} \
\
return nil; \
} \
\
- (id)copyWithZone:(NSZone *)zone \
{ \
return self; \
} \
\
- (id)retain \
{ \
return self; \
} \
\
- (NSUInteger)retainCount \
{ \
return NSUIntegerMax; \
} \
\
- (void)release \
{ \
} \
\
- (id)autorelease \
{ \
return self; \
}


If you #import this header at the top of a class implementation, then all you need to do is write:

SYNTHESIZE_SINGLETON_FOR_CLASS(MyClassName);

inside the @implementation MyClassName declaration and your class will become a singleton. You will also need to add the line:

+ (MyClassName *)sharedMyClassName;

to the header file for MyClassName so the singleton accessor method can be found from other source files if they #import the header.

Once your class is a singleton, you can access the instance of it using the line:

[MyClassName sharedMyClassName];
Note: A singleton does not need to be explicitly allocated or initialized (the alloc and init methods will be called automatically on first access) but you can still implement the default init method if you want to perform initialization.

How to Create, Load, and Use Multiple Nib Files

In Mac OS X, application management is a single drag & drop operation: drop the application into /Applications to install, and drop it into the Trash to uninstall. This simplicity and power is just the tip of the iceberg. What we're seeing is just one use of a more general facility Cocoa calls bundles.

This article is about Nib files, and how to use them in your applications. Nib files are just specialized bundles, so we'll talk about bundles first.

// Bundles

A bundle is a directory containing code and resources. Applications, frameworks, Interface Builder (IB) Interface Palettes, and Nibs are all bundle types. The NSBundle Foundation class, along with the NSBundle Additions found in Cocoa, allow you to easily access and load a bundle's contents.

Getting a reference for your application's NSBundle is easy:

NSBundle * b = [NSBundle mainBundle];

Getting a reference for a given bundle inside your application is equally easy:

NSBundle * c = [NSBundle bundleWithPath:
[b pathForResource:@"TestBundle" ofType:@"bundle"]];

pathForResource:ofType: finds a given resource inside the receiving NSBundle's bundle directory, whether that resource is represented on disk as a file or directory.

Also, you can load a bundle's Principal Class, which is typically the first class listed in Project Builder(PB)'s "Files" tab for non-.app bundles. Say I had a class called BundleClass, and I ran the following code (after running all the code above):

bundleClass = NSAllocateObject([c principalClass], 0, NSDefaultMallocZone());
NSLog(@"loaded class %@", bundleClass);
[bundleClass init];

The output of my program would have been:

2002-03-23 15:29:20.637 Test[4709]  loaded class 

Suffice it to say, NSBundle is cool, and is the basis for applications, frameworks, Nibs, and a few other types of packaged data. There are plenty of useful methods for dealing with NSBundles, so do yourself a favor and check out the documentation.

// Nibs: A Special Type of Bundle

Now we come to the meat of this article: Nib files. Nib files are bundles that contain resources created by Interface Builder (IB). When you create a new Cocoa project, one Nib, MainMenu.nib, is automatically created for you. In MainMenu.nib, you can setup a menu bar (duh) and any additional windows, panels, or drawers you want.

Nibs contain archived instances of all the objects you built in IB. This includes instances of NSMenu, NSWindow, and any of your own classes you instanciate in IB. Once the Nib is loaded, every instance archived within it is unarchived into a running instance.

But, what do you do when you want a variable number of instances for a given window or set of windows? For example, for the document window in MDI applications like TextEdit? This is where we have to use more than one Nib file.

// Making a New Nib

Using a Nib is simple, in fact we all do it every time we make a new Cocoa application. Using more than one Nib is almost as simple: just create one with your original application in Project Builder (PB). Choose "Cocoa Document-based Application" under File..New Project. Under the "Resources" group in your newly-created project, you'll see MyDocument.nib. MyDocument.nib is a Nib loaded for each individual document opened in the application.

The other way to add a Nib is just to create a new one in Interface Builder (IB) and add it to your project. In IB, just hit File -> New -> Cocoa -> Empty, save it, and add it to your project.

// Multiple Client Windows Made Easy

Now that you've got a bright shiny new Nib, it would probably help to be able to do something with it. But how do you get references to all the stuff inside the Nib once you load it? In your new Nib, you'll see an object instance called "File Owner." This instance is there to hold a set of references for the newly created objects unarchived from the Nib you just loaded. You can add outlets and actions to it like any other object.

So, build your Nib like any other, and then connect everything you need externally accessible to File Owner. You can also set File Owner's class to anything you want. You can leave it as NSObject, set it to NSDocument like in the MyDocument.nib created in Project Builder (PB), or make it your own class. It's infinitely flexible, go have some fun with it.

So, all this talk and still no code? Here's how you load the Nib into your application:

- (void) newDocument:(id) sender {
MyDocument *d = [[MyDocument alloc] init];
if (![NSBundle loadNibNamed:@"MyDocument" owner:d]) {
NSLog(@"Error loading Nib for document!");
} else {
[d doSomething];
[_list_of_open_documents addObject:d];
}
}

Ok, so only the single call to loadNibNamed:owner: is necessary, but error checking never hurt nobody.

The code above fills in d's outlets with those specified in the Nib. d becomes the File Owner, and so it takes on all the File Owner's connections in the Nib.

источник: www.cocoadevcentral.com

Powered by Blogger.