Fixes inEOAttribute.m and EOKeyValueARchiver.m

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gdl2/trunk@21153 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Manuel Guesdon 2005-04-24 11:28:15 +00:00
parent 8bab203b96
commit 9c4a91f7ce
4 changed files with 420 additions and 173 deletions

View file

@ -1,3 +1,20 @@
2005-04-20 Manuel Guesdon <mguesdon@orange-concept.com>
* EOControl/EOPriv.h: added GDL2_allocWithZone()
* EOAccess/EOAttribute.m:
o fixed -validateValue: rewritten following
David Ayers's advices to handle EONull values
validation and fix width validation
o fixed -newValueForBytes:length: retain problems and
wrong invocation target
o fixed -newValueForBytes:length:encoding: retain
problems and wrong invocation target
o added comments and doc
o added allowsNull in EOAttribute -description
* EOControl/EOKeyValueArchiver.m: fixed int and bool
archiving following David Ayers's comments (produce
NSNumber instead of NSString)
2005-04-24 Matt Rice <ratmice@yahoo.com> 2005-04-24 Matt Rice <ratmice@yahoo.com>
* EOAdaptors/Postgres95/Postgres95Adaptor.m: Removed externalTypeNames * EOAdaptors/Postgres95/Postgres95Adaptor.m: Removed externalTypeNames

View file

@ -441,10 +441,11 @@ RCS_ID("$Id$")
[self columnName], [self columnName],
[self definition]]; [self definition]];
dscr = [dscr stringByAppendingFormat: @"valueClassName=%@ valueType=%@ externalType=%@ isReadOnly=%s isDerived=%s isFlattened=%s>", dscr = [dscr stringByAppendingFormat: @"valueClassName=%@ valueType=%@ externalType=%@ allowsNull=%s isReadOnly=%s isDerived=%s isFlattened=%s>",
[self valueClassName], [self valueClassName],
[self valueType], [self valueType],
[self externalType], [self externalType],
([self allowsNull] ? "YES" : "NO"),
([self isReadOnly] ? "YES" : "NO"), ([self isReadOnly] ? "YES" : "NO"),
([self isDerived] ? "YES" : "NO"), ([self isDerived] ? "YES" : "NO"),
([self isFlattened] ? "YES" : "NO")]; ([self isFlattened] ? "YES" : "NO")];
@ -1078,17 +1079,18 @@ return nexexp
/** /**
* Returns an NSString or a custom-class value object * Returns an NSData or a custom-class value object
* from the supplied set of bytes. * from the supplied set of bytes.
* The Adaptor calls this method during value creation * The Adaptor calls this method during value creation
* when fetching objects from the database. * when fetching objects from the database.
* For efficiency, the returned value is NOT autoreleased. * For efficiency, the returned value is NOT autoreleased.
*
* NB: The documentation of the reference implementation
* mistakenly claims that it returns an NSString.
**/ **/
- (id)newValueForBytes: (const void *)bytes - (id)newValueForBytes: (const void *)bytes
length: (int)length length: (int)length
{ {
NSMethodSignature *aSignature;
NSInvocation *anInvocation;
NSData *value = nil; NSData *value = nil;
Class valueClass = [self _valueClass]; Class valueClass = [self _valueClass];
@ -1097,43 +1099,79 @@ return nexexp
switch (_argumentType) switch (_argumentType)
{ {
case EOFactoryMethodArgumentIsNSData: case EOFactoryMethodArgumentIsNSData:
{
//For efficiency reasons, the returned value is NOT autoreleased ! //For efficiency reasons, the returned value is NOT autoreleased !
value = [GDL2_alloc(NSData) initWithBytes: bytes length: length]; value = [GDL2_alloc(NSData) initWithBytes: bytes length: length];
// If we have a value factiry method, call it to get the final value
if(_valueFactoryMethod != NULL) if(_valueFactoryMethod != NULL)
{ {
//TODO: doc says that the returned value is autoreleased !! NSData* tmp = value;
// valueFactoryMethod returns an autoreleased value
value = [(id)valueClass performSelector: _valueFactoryMethod value = [(id)valueClass performSelector: _valueFactoryMethod
withObject: [value autorelease]]; withObject: value];
if (value != value)
{
RETAIN(value);
RELEASE(tmp);
}; };
};
break; break;
}
case EOFactoryMethodArgumentIsBytes: case EOFactoryMethodArgumentIsBytes:
//For efficiency reasons, the returned value is NOT autoreleased ! {
value = [valueClass allocWithZone: 0]; NSMethodSignature *aSignature = nil;
NSInvocation *anInvocation = nil;
// TODO: verify with WO
NSAssert2(_valueFactoryMethod,
@"No _valueFactoryMethod (valueFactoryMethodName=%@) in attribute %@",
_valueFactoryMethodName,self);
// First find signature for method
aSignature = aSignature =
[valueClass [valueClass
instanceMethodSignatureForSelector: _valueFactoryMethod]; methodSignatureForSelector: _valueFactoryMethod];
// Create the invocation object
anInvocation anInvocation
= [NSInvocation invocationWithMethodSignature: aSignature]; = [NSInvocation invocationWithMethodSignature: aSignature];
// Put the selector
[anInvocation setSelector: _valueFactoryMethod]; [anInvocation setSelector: _valueFactoryMethod];
[anInvocation setTarget: value];
// The target is the custom value class
[anInvocation setTarget: valueClass];
// arguments are buffer pointer and length
[anInvocation setArgument: &bytes atIndex: 2]; [anInvocation setArgument: &bytes atIndex: 2];
[anInvocation setArgument: &length atIndex: 3]; [anInvocation setArgument: &length atIndex: 3];
[anInvocation invoke];
break;
// Let's invoke the method
[anInvocation invoke];
// Get the returned value
[anInvocation getReturnValue: &value];
//For efficiency reasons, the returned value is NOT autoreleased !
// valueFactoryMethod returns an autoreleased value
RETAIN(value);
break;
}
case EOFactoryMethodArgumentIsNSString: case EOFactoryMethodArgumentIsNSString:
// TODO: verify with WO
break; break;
} }
} }
if(!value) if(!value)
{
//For efficiency reasons, the returned value is NOT autoreleased ! //For efficiency reasons, the returned value is NOT autoreleased !
value = [GDL2_alloc(NSData) initWithBytes: bytes length: length]; value = [GDL2_alloc(NSData) initWithBytes: bytes length: length];
}
return value; return value;
} }
@ -1149,9 +1187,7 @@ return nexexp
length: (int)length length: (int)length
encoding: (NSStringEncoding)encoding encoding: (NSStringEncoding)encoding
{ {
NSMethodSignature *aSignature; NSString* value = nil;
NSInvocation *anInvocation;
id value = nil;
Class valueClass = [self _valueClass]; Class valueClass = [self _valueClass];
if (valueClass != Nil && valueClass != GDL2_NSStringClass) if (valueClass != Nil && valueClass != GDL2_NSStringClass)
@ -1160,40 +1196,79 @@ return nexexp
{ {
case EOFactoryMethodArgumentIsNSString: case EOFactoryMethodArgumentIsNSString:
{ {
NSData *data; NSData *data = nil;
NSString *string; NSString *string = nil;
//For efficiency reasons, the returned value is NOT autoreleased !
data = AUTORELEASE([(GDL2_alloc(NSData)) initWithBytes: bytes data = AUTORELEASE([(GDL2_alloc(NSData)) initWithBytes: bytes
length: length]); length: length]);
string = AUTORELEASE([(GDL2_alloc(NSString)) initWithData: data
encoding: encoding]);
string = [(GDL2_alloc(NSString)) initWithData: data
encoding: encoding];
// If we have a value factiry method, call it to get the final value
if(_valueFactoryMethod != NULL)
{
value = [((id)valueClass) performSelector: _valueFactoryMethod value = [((id)valueClass) performSelector: _valueFactoryMethod
withObject: string]; withObject: string];
if ( value != string)
{
//For efficiency reasons, the returned value is NOT autoreleased !
RETAIN(value);
RELEASE(string);
};
}
else
{
//For efficiency reasons, the returned value is NOT autoreleased !
value = string;
};
break; break;
} }
case EOFactoryMethodArgumentIsBytes: case EOFactoryMethodArgumentIsBytes:
{ {
//For efficiency reasons, the returned value is NOT autoreleased ! NSMethodSignature *aSignature = nil;
value = [valueClass alloc]; NSInvocation *anInvocation = nil;
// TODO: verify with WO
NSAssert2(_valueFactoryMethod,
@"No _valueFactoryMethod (valueFactoryMethodName=%@) in attribute %@",
_valueFactoryMethodName,self);
// First find signature for method
aSignature aSignature
= [valueClass instanceMethodSignatureForSelector: _valueFactoryMethod]; = [valueClass methodSignatureForSelector: _valueFactoryMethod];
// Create the invocation object
anInvocation anInvocation
= [NSInvocation invocationWithMethodSignature: aSignature]; = [NSInvocation invocationWithMethodSignature: aSignature];
// Put the selector
[anInvocation setSelector: _valueFactoryMethod]; [anInvocation setSelector: _valueFactoryMethod];
[anInvocation setTarget: value];
// The target is the custom value class
[anInvocation setTarget: valueClass];
// arguments are buffer pointer, length and encoding
[anInvocation setArgument: &bytes atIndex: 2]; [anInvocation setArgument: &bytes atIndex: 2];
[anInvocation setArgument: &length atIndex: 3]; [anInvocation setArgument: &length atIndex: 3];
[anInvocation setArgument: &encoding atIndex: 4]; [anInvocation setArgument: &encoding atIndex: 4];
// Let's invoke the method
[anInvocation invoke]; [anInvocation invoke];
// Get the returned value
[anInvocation getReturnValue: &value];
//For efficiency reasons, the returned value is NOT autoreleased !
// valueFactoryMethod returns an autoreleased value
RETAIN(value);
break; break;
} }
case EOFactoryMethodArgumentIsNSData: case EOFactoryMethodArgumentIsNSData:
// TODO: verify with WO
break; break;
} }
} }
@ -1201,9 +1276,10 @@ return nexexp
if(!value) if(!value)
{ {
NSData *data; NSData *data;
//For efficiency reasons, the returned value is NOT autoreleased !
data = AUTORELEASE([(GDL2_alloc(NSData)) initWithBytes: bytes data = AUTORELEASE([(GDL2_alloc(NSData)) initWithBytes: bytes
length: length]); length: length]);
//For efficiency reasons, the returned value is NOT autoreleased !
value = [(GDL2_alloc(NSString)) initWithData: data value = [(GDL2_alloc(NSString)) initWithData: data
encoding: encoding]; encoding: encoding];
} }
@ -1217,6 +1293,8 @@ return nexexp
* The Adaptor calls this method during value creation * The Adaptor calls this method during value creation
* when fetching objects from the database. * when fetching objects from the database.
* For efficiency, the returned value is NOT autoreleased. * For efficiency, the returned value is NOT autoreleased.
* Milliseconds are dropped since they cannot be easily be stored in
* NSCalendarDate.
**/ **/
- (NSCalendarDate *)newDateForYear: (int)year - (NSCalendarDate *)newDateForYear: (int)year
month: (unsigned)month month: (unsigned)month
@ -1228,10 +1306,12 @@ return nexexp
timezone: (NSTimeZone *)timezone timezone: (NSTimeZone *)timezone
zone: (NSZone *)zone zone: (NSZone *)zone
{ {
NSCalendarDate *date; NSCalendarDate *date = nil;
// FIXME: extend initializer to include Milliseconds
//For efficiency reasons, the returned value is NOT autoreleased ! //For efficiency reasons, the returned value is NOT autoreleased !
date = [[GDL2_NSCalendarDateClass allocWithZone: zone] date = [(GDL2_allocWithZone(NSCalendarDate,zone))
initWithYear: year initWithYear: year
month: month month: month
day: day day: day
@ -1240,8 +1320,6 @@ return nexexp
second: second second: second
timeZone: timezone]; timeZone: timezone];
// TODO milliseconds ??
return date; return date;
} }
@ -1410,6 +1488,23 @@ EOAdaptorDateType Date value (attribute valueClass is kind of NSDate)
return _adaptorValueType; return _adaptorValueType;
} }
/** Returns the type of argument needed by the factoryMethod.
Type can be:
EOFactoryMethodArgumentIsNSData
method need one parameter: a NSData
EOFactoryMethodArgumentIsNSString
method need one parameter: a NSString
EOFactoryMethodArgumentIsBytes
method need 2 parameters (for data type valueClass): a raw bytes buffer and its length
or 3 parameters (for string type valueClass): a raw bytes buffer, its length and the encoding
See also: -valueFactoryMethod, -setFactoryMethodArgumentType:
**/
- (EOFactoryMethodArgumentType)factoryMethodArgumentType - (EOFactoryMethodArgumentType)factoryMethodArgumentType
{ {
return _argumentType; return _argumentType;
@ -1432,6 +1527,13 @@ See also: -setFactoryMethodArgumentType:
_valueFactoryMethod = NSSelectorFromString(_valueFactoryMethodName); _valueFactoryMethod = NSSelectorFromString(_valueFactoryMethodName);
} }
/** Set method name to use to convert value of a class
different than attribute adaptor value type.
See also: -adaptorValueByConvertingAttributeValue, -adaptorValueConversionMethod,
-adaptorValueConversionMethodName
**/
- (void)setAdaptorValueConversionMethodName: (NSString *)conversionMethodName - (void)setAdaptorValueConversionMethodName: (NSString *)conversionMethodName
{ {
[self willChange]; [self willChange];
@ -1440,6 +1542,22 @@ See also: -setFactoryMethodArgumentType:
_adaptorValueConversionMethod = NSSelectorFromString(_adaptorValueConversionMethodName); _adaptorValueConversionMethod = NSSelectorFromString(_adaptorValueConversionMethodName);
} }
/** Set the type of argument needed by the factoryMethod.
Type can be:
EOFactoryMethodArgumentIsNSData
method need one parameter: a NSData
EOFactoryMethodArgumentIsNSString
method need one parameter: a NSString
EOFactoryMethodArgumentIsBytes
method need 2 parameters (for data type valueClass): a raw bytes buffer and its length
or 3 parameters (for string type valueClass): a raw bytes buffer, its length and the encoding
See also: -setValueFactoryMethodName:, -factoryMethodArgumentType
**/
- (void)setFactoryMethodArgumentType: (EOFactoryMethodArgumentType)argumentType - (void)setFactoryMethodArgumentType: (EOFactoryMethodArgumentType)argumentType
{ {
[self willChange]; [self willChange];
@ -1451,34 +1569,90 @@ See also: -setFactoryMethodArgumentType:
@implementation EOAttribute (EOAttributeValueMapping) @implementation EOAttribute (EOAttributeValueMapping)
/** Validates value pointed by valueP, may set changed validated value in
valueP and return an validation exception if constraints validation fails.
valueP must not be NULL.
More details:
1. raise an exception if [self allowsNull] == NO but *valueP is nil or EONull
except if attribute is a primaryKey attribute (reason of this process
exception is currently unknown).
2. if valueClassName isn't set, return nil and leave *valueP unchanged
3. if it can't find the class by name, log message, return nil and
leave *valueP unchanged
4. do the fancy type conversions as necessary (Pretty much the current
handling we have)
5. THEN if width is not 0 call adaptorValueByConvertingAttributeValue:
on the new value and the if returned value is NSString or NSData
validate length with width and return a corresponding exception
if it's longer than allowed.
**/
- (NSException *)validateValue: (id*)valueP - (NSException *)validateValue: (id*)valueP
{ {
NSException *exception=nil; NSException *exception=nil;
NSAssert(valueP, @"No value pointer"); NSAssert(valueP, @"No value pointer");
if (*valueP == nil && [self allowsNull] == NO) NSDebugMLog(@"In EOAttribute validateValue: value (class=%@) = %@ attribute = %@",
exception = [NSException validationExceptionWithFormat: @"attribute '%@' cannot be nil", [self name]]; [*valueP class],*valueP,self);
else if (*valueP)
{
//call self valueClassName
*valueP = [self adaptorValueByConvertingAttributeValue: *valueP];
//call attribute width
//end !
//TODO: revoir // First check if value is nil or EONull
if (_isNilOrEONull(*valueP))
{ {
//EOEntity *entity = [self entity]; // Check if this is not allowed
//NSArray *pkAttributes = [entity primaryKeyAttributes]; if ([self allowsNull] == NO)
//TODO wowhat {
NSArray *pkAttributes = [[self entity] primaryKeyAttributes];
if (*valueP) // "Primary key attributes are ignored when enforcing allowsNull
// property for attributes. The values could be handled later
// by automatic PK-generation later
if ([pkAttributes indexOfObjectIdenticalTo: self] == NSNotFound)
{ {
Class valueClass = [self _valueClass]; exception =
[NSException
validationExceptionWithFormat:
@"attribute '%@' of entity '%@' cannot be nil or EONull ",
[self name],[[self entity] name]];
};
}
}
else // There's a value.
{
NSString* valueClassName=[self valueClassName];
if ([*valueP isKindOfClass: valueClass] == NO) // if there's no valueClassName, leave the value unchanged
// and don't return an exception
if (valueClassName)
{ {
if ([*valueP isKindOfClass: GDL2_NSStringClass]) Class valueClass=[self _valueClass];
// There's a className but no class !
if (!valueClass)
{
//Log this problem, leave the value unchanged
// and don't return an exception
NSLog(@"No valueClass for valueClassName '%@' in attribute %@",
valueClassName,self);
}
else
{
unsigned int width = 0;
IMP isKindOfClassIMP=[*valueP methodForSelector:@selector(isKindOfClass:)];
// If the value has not the good class we'll try to convert it
if ((*isKindOfClassIMP)(*valueP,@selector(isKindOfClass:),
valueClass) == NO)
{
// Is it a string ?
if ((*isKindOfClassIMP)(*valueP,@selector(isKindOfClass:),
GDL2_NSStringClass))
{ {
if (valueClass == GDL2_NSNumberClass) if (valueClass == GDL2_NSNumberClass)
{ {
@ -1486,89 +1660,139 @@ See also: -setFactoryMethodArgumentType:
switch(valueTypeChar) switch(valueTypeChar)
{ {
case 'i': case 'i':
*valueP = [NSNumber numberWithInt: *valueP = [GDL2_alloc(NSNumber)
initWithInt:
[*valueP intValue]]; [*valueP intValue]];
AUTORELEASE(*valueP);
break; break;
case 'I': case 'I':
*valueP = [NSNumber numberWithUnsignedInt: *valueP = [GDL2_alloc(NSNumber)
initWithUnsignedInt:
[*valueP unsignedIntValue]]; [*valueP unsignedIntValue]];
AUTORELEASE(*valueP);
break; break;
case 'c': case 'c':
*valueP = [NSNumber numberWithChar: *valueP = [GDL2_alloc(NSNumber)
initWithChar:
[*valueP intValue]]; [*valueP intValue]];
AUTORELEASE(*valueP);
break; break;
case 'C': case 'C':
*valueP = [NSNumber numberWithUnsignedChar: *valueP = [GDL2_alloc(NSNumber)
initWithUnsignedChar:
[*valueP unsignedIntValue]]; [*valueP unsignedIntValue]];
AUTORELEASE(*valueP);
break; break;
case 's': case 's':
*valueP = [NSNumber numberWithShort: *valueP = [GDL2_alloc(NSNumber)
initWithShort:
[*valueP shortValue]]; [*valueP shortValue]];
AUTORELEASE(*valueP);
break; break;
case 'S': case 'S':
*valueP = [NSNumber numberWithUnsignedShort: *valueP = [GDL2_alloc(NSNumber)
initWithUnsignedShort:
[*valueP unsignedShortValue]]; [*valueP unsignedShortValue]];
AUTORELEASE(*valueP);
break; break;
case 'l': case 'l':
*valueP = [NSNumber numberWithLong: *valueP = [GDL2_alloc(NSNumber)
initWithLong:
[*valueP longValue]]; [*valueP longValue]];
AUTORELEASE(*valueP);
break; break;
case 'L': case 'L':
*valueP = [NSNumber numberWithUnsignedLong: *valueP = [GDL2_alloc(NSNumber)
initWithUnsignedLong:
[*valueP unsignedLongValue]]; [*valueP unsignedLongValue]];
AUTORELEASE(*valueP);
break; break;
case 'u': case 'u':
*valueP = [NSNumber numberWithLongLong: *valueP = [GDL2_alloc(NSNumber)
initWithLongLong:
[*valueP longLongValue]]; [*valueP longLongValue]];
AUTORELEASE(*valueP);
break; break;
case 'U': case 'U':
*valueP = [NSNumber numberWithUnsignedLongLong: *valueP = [GDL2_alloc(NSNumber)
initWithUnsignedLongLong:
[*valueP unsignedLongLongValue]]; [*valueP unsignedLongLongValue]];
AUTORELEASE(*valueP);
break; break;
case 'f': case 'f':
*valueP = [NSNumber numberWithFloat: *valueP = [GDL2_alloc(NSNumber)
initWithFloat:
[*valueP floatValue]]; [*valueP floatValue]];
AUTORELEASE(*valueP);
break; break;
default: default:
*valueP = [NSNumber numberWithDouble: *valueP = [GDL2_alloc(NSNumber)
initWithDouble:
[*valueP doubleValue]]; [*valueP doubleValue]];
AUTORELEASE(*valueP);
break; break;
}; };
} }
else if (valueClass == GDL2_NSDecimalNumberClass) else if (valueClass == GDL2_NSDecimalNumberClass)
*valueP = [NSDecimalNumber {
decimalNumberWithString: *valueP]; *valueP = [GDL2_alloc(NSDecimalNumber)
initWithString: *valueP];
AUTORELEASE(*valueP);
}
else if (valueClass == GDL2_NSDataClass) else if (valueClass == GDL2_NSDataClass)
{
//TODO Verify here.
*valueP = [*valueP *valueP = [*valueP
dataUsingEncoding: NSASCIIStringEncoding dataUsingEncoding:
allowLossyConversion: YES]; [NSString defaultCStringEncoding]];
}
else if (valueClass == GDL2_NSCalendarDateClass) else if (valueClass == GDL2_NSCalendarDateClass)
{
*valueP = AUTORELEASE([(GDL2_alloc(NSCalendarDate)) *valueP = AUTORELEASE([(GDL2_alloc(NSCalendarDate))
initWithString: *valueP]); initWithString: *valueP]);
} }
} }
else };
{
if ([*valueP isKindOfClass: GDL2_NSStringClass])
{
unsigned width = [self width];
if (width && [*valueP length] > width) // Now, test width if any
{ width = [self width];
const char *buf;
buf = [*valueP cString]; if (width>0)
*valueP = [NSString stringWithCString: buf
length: width];
}
}
else if ([*valueP isKindOfClass: GDL2_NSNumberClass])
{ {
// TODO ?? // First convert value to adaptor value
} id testValue = [self adaptorValueByConvertingAttributeValue: *valueP];
}
if (testValue)
{
IMP testIsKindOfClassIMP=[testValue methodForSelector:@selector(isKindOfClass:)];
// We can test NSString and NSData type only
if ((*testIsKindOfClassIMP)(testValue,@selector(isKindOfClass:),
GDL2_NSStringClass)
|| (*testIsKindOfClassIMP)(testValue,@selector(isKindOfClass:),
GDL2_NSDataClass))
{
unsigned int testValueLength = [testValue length];
if (testValueLength > width)
{
exception = [NSException validationExceptionWithFormat:
@"Value %@ for attribute '%@' is too large",
testValue,[self name]];
};
};
};
};
} }
} }
} }

View file

@ -68,6 +68,7 @@ RCS_ID("$Id$")
#include <Foundation/NSDictionary.h> #include <Foundation/NSDictionary.h>
#include <Foundation/NSException.h> #include <Foundation/NSException.h>
#include <Foundation/NSDebug.h> #include <Foundation/NSDebug.h>
#include <Foundation/NSValue.h>
#else #else
#include <Foundation/Foundation.h> #include <Foundation/Foundation.h>
#endif #endif
@ -205,8 +206,8 @@ RCS_ID("$Id$")
NSDebugMLLog(@"gsdb", @"key=%@ intValue=%d",key,intValue); NSDebugMLLog(@"gsdb", @"key=%@ intValue=%d",key,intValue);
NSAssert(key,@"No key"); NSAssert(key,@"No key");
[_propertyList setObject:[NSString stringWithFormat:@"%d",intValue] [_propertyList setObject: [NSNumber numberWithInt: intValue]
forKey:key]; forKey: key];
NSDebugMLLog(@"gsdb", @"_propertyList=%@",_propertyList); NSDebugMLLog(@"gsdb", @"_propertyList=%@",_propertyList);
@ -222,8 +223,8 @@ RCS_ID("$Id$")
NSDebugMLLog(@"gsdb", @"key=%@ yn=%s",key,(yn ? "YES" : "NO")); NSDebugMLLog(@"gsdb", @"key=%@ yn=%s",key,(yn ? "YES" : "NO"));
NSAssert(key,@"No key"); NSAssert(key,@"No key");
[_propertyList setObject:(yn ? @"YES" : @"NO") [_propertyList setObject: [NSNumber numberWithBool: yn]
forKey:key]; forKey: key];
NSDebugMLLog(@"gsdb", @"_propertyList=%@",_propertyList); NSDebugMLLog(@"gsdb", @"_propertyList=%@",_propertyList);

View file

@ -119,6 +119,11 @@ _isNilOrEONull(id obj)
(*GDL2_##CLASS_NAME##_allocWithZoneIMP) \ (*GDL2_##CLASS_NAME##_allocWithZoneIMP) \
(GDL2_##CLASS_NAME##Class,@selector(allocWithZone:),NULL) (GDL2_##CLASS_NAME##Class,@selector(allocWithZone:),NULL)
// ---- +allocWithZone: ----
#define GDL2_allocWithZone(CLASS_NAME,ALLOC_ZONE) \
(*GDL2_##CLASS_NAME##_allocWithZoneIMP) \
(GDL2_##CLASS_NAME##Class,@selector(allocWithZone:),ALLOC_ZONE)
// ---- NSMutableString appendString: ---- // ---- NSMutableString appendString: ----
#define GDL2_AppendStringWithImp(string,methodIMP,aString) \ #define GDL2_AppendStringWithImp(string,methodIMP,aString) \
(*(methodIMP))((string),@selector(appendString:),(aString)) (*(methodIMP))((string),@selector(appendString:),(aString))