Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Element.m
/* |
File: Element.m |
Abstract: Root class for the scriptable objects in this sample. |
Version: 1.2 |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple |
Inc. ("Apple") in consideration of your agreement to the following |
terms, and your use, installation, modification or redistribution of |
this Apple software constitutes acceptance of these terms. If you do |
not agree with these terms, please do not use, install, modify or |
redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and |
subject to these terms, Apple grants you a personal, non-exclusive |
license, under Apple's copyrights in this original Apple software (the |
"Apple Software"), to use, reproduce, modify and redistribute the Apple |
Software, with or without modifications, in source and/or binary forms; |
provided that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the following |
text and disclaimers in all such redistributions of the Apple Software. |
Neither the name, trademarks, service marks or logos of Apple Inc. may |
be used to endorse or promote products derived from the Apple Software |
without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or |
implied, are granted by Apple herein, including but not limited to any |
patent rights that may be infringed by your derivative works or by other |
works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. |
Copyright (C) 2011 Apple Inc. All Rights Reserved. |
*/ |
#import "Element.h" |
#import "scriptLog.h" |
#include <sys/types.h> |
#include <unistd.h> |
@implementation Element |
/* Instead of sythesizing our properties here, we implement them manually |
in order to perform logging for debugging purposes. */ |
/* storage management |
The normal sequence of events when an object is created is as follows: |
1. an AppleScript 'make' command will allocate and initialize an instance |
of the class it has been asked to create. For example, it may create a Trinket. |
2. then it will call the insertInXXXXX: insertInXXXXX:atIndex: method on the container |
object where the new object will be stored. For example, if we were being asked |
to create a Trinket in a Bucket, then the make command would create an instance |
of Trinket and then it would call insertInTrinkets: on the Bucket object. |
3. Inside of the insertInXXXXX: or insertInXXXXX:atIndex: you must record the |
parent object and the parent's property key for the new object being created so |
you can create a objectSpecifier later. In this class, we have defined the |
setContainer:andProperty: for that purpose. For example, inside of our |
insertInTrinkets: method on our Bucket object, we the setContainer:andProperty: |
method on the trinket object like so: |
[trinket setContainer:self andProperty:@"trinkets"] |
to inform the trinket object who its container is and the name of the Cocoa key |
on that container object used for the list of trinkets. |
*/ |
-(id) init { |
if ((self = [super init])) { |
static unsigned long gNameCounter = 1; |
/* calkl our unique id generator to make a new id */ |
self.uniqueID = [Element calculateNewUniqueID]; |
/* we use a global counter to generate unique names */ |
self.name = [NSString stringWithFormat:@"Untitled %d", gNameCounter++]; |
} |
/* I put the logging statement later after the initialization so we can see |
the uniqueID */ |
SLOG(@"init element %@", self.uniqueID); |
return self; |
} |
/* standard deallocation of our members followed by superclass. |
nothing out of the ordinary here. */ |
- (void) dealloc { |
SLOG(@"dealloc element %@", self.uniqueID); |
self.uniqueID = nil; |
[container release]; |
[containerProperty release]; |
self.name = nil; |
[super dealloc]; |
} |
/* calculateNewUniqueID returns a new unique id value that can be used |
to uniquely idenfity an scriptable object. Our main concern here is that the |
id value be unique within our process AND that it is unique to the specific |
instance of our process (in case our application is re-launched for some reason |
while a script is running). |
To guarantee uniqueness within our process, we use a simple counting global |
variable, and to guarantee the values we return are unique to our process instance |
we mix in our process id number. |
For convenience and ease of idenfification, I put the application's initials at the |
beginning of the id string. */ |
+ (NSString *)calculateNewUniqueID { |
static unsigned long gElementCounter; /* our element id generator */ |
static pid_t gMyProcessID; /* unique id of our process */ |
static BOOL gUniqueInited = NO; /* our element id generator */ |
NSString* theID; |
/* set up code for our id generator */ |
if ( ! gUniqueInited ) { |
gMyProcessID = getpid(); /* guaranteed unique for our process, see man getpid */ |
gElementCounter = 1; /* guaranteed unique within our process */ |
gUniqueInited = YES; |
} |
/* we'll return unique id values as strings composed of the process id followed |
by a unique count value. see the man page for getpid for more info about process |
id values. */ |
theID = [NSString stringWithFormat:@"SSO-%d-%d", gMyProcessID, gElementCounter++]; |
SLOG(@"new unique id ='%@'", theID); |
return theID; |
} |
/* standard setter and getter methods for the container and |
containerProperty slots. The only thing that's unusual here is that |
we have lumped the setter functions together because we will always |
call them together. */ |
- (id)container { |
SLOG(@" of %@ as %@", self.uniqueID, container); |
return [[container retain] autorelease]; |
} |
- (NSString *)containerProperty { |
SLOG(@" return %@ as '%@'", self.uniqueID, containerProperty); |
return [[containerProperty retain] autorelease]; |
} |
- (void)setContainer:(id)value andProperty:(NSString *)property { |
SLOG(@" of %@ to %@ and '%@'", self.uniqueID, [value class], property); |
if (container != value) { |
[container release]; |
container = [value retain]; |
} |
if (containerProperty != property) { |
[containerProperty release]; |
containerProperty = [property copy]; |
} |
} |
/* standard setter and getter methods for the 'uniqueID' property |
nothing out of the ordinary here. */ |
- (NSString *)uniqueID { |
return [[uniqueID retain] autorelease]; |
} |
- (void)setUniqueID:(NSString *)value { |
SLOG(@" of %@ to '%@'", self.uniqueID, value); |
if (uniqueID != value) { |
[uniqueID release]; |
uniqueID = [value copy]; |
} |
} |
/* standard setter and getter methods for the 'name' property |
nothing out of the ordinary here. */ |
- (NSString *)name { |
SLOG(@" of %@ as '%@'", self.uniqueID, name); |
return [[name retain] autorelease]; |
} |
- (void)setName:(NSString *)value { |
SLOG(@" of %@ to '%@'", self.uniqueID, value); |
if (name != value) { |
[name release]; |
name = [value copy]; |
} |
} |
/* calling objectSpecifier asks an object to return an object specifier |
record referring to itself. You must call setContainer:andProperty: before |
you can call this method. */ |
- (NSScriptObjectSpecifier *)objectSpecifier { |
SLOG(@" of %@ ", self.uniqueID); |
return [[NSUniqueIDSpecifier allocWithZone:[self zone]] |
initWithContainerClassDescription:(NSScriptClassDescription*) [self.container classDescription] |
containerSpecifier:[self.container objectSpecifier] |
key:self.containerProperty uniqueID:self.uniqueID]; |
} |
@end |
Copyright © 2011 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2011-09-07