Move _customClasses to GSXibKeyedUnarchiver and implement logic to build the _customClasses array for use in Gorm when loading the xib file.

This commit is contained in:
Gregory John Casamento 2022-03-26 11:19:59 -04:00
parent def2c9765d
commit 790b686f0d
4 changed files with 88 additions and 19 deletions

View file

@ -41,6 +41,7 @@
NSMutableArray *stack;
GSXibElement *currentElement;
NSMutableDictionary *decoded;
NSMutableArray *_customClasses;
}
+ (BOOL) checkXib5: (NSData *)data;
@ -53,6 +54,7 @@
- (id) _decodeArrayOfObjectsForElement: (GSXibElement*)element;
- (id) _decodeDictionaryOfObjectsForElement: (GSXibElement*)element;
- (id) objectForXib: (GSXibElement*)element;
- (NSArray *) customClasses;
- (NSDictionary *) decoded;
@end

View file

@ -41,9 +41,7 @@
GSXibElement *_runtimeAttributes;
NSMutableDictionary *_orderedObjectsDict;
NSArray *_resources;
NSMutableArray *_customClasses;
}
- (NSRange) decodeRangeForKey: (NSString*)key;
- (NSMutableArray *) customClasses;
@end

View file

@ -750,9 +750,6 @@ static NSArray *XmlBoolDefaultYes = nil;
[_IBObjectContainer setElement: _connectionRecords forKey: @"connectionRecords"];
[_IBObjectContainer setElement: _objectRecords forKey: @"objectRecords"];
[_IBObjectContainer setElement: _flattenedProperties forKey: @"flattenedProperties"];
// Hold the dictionary which contains custom class information for Gorm/IB.
_customClasses = [[NSMutableArray alloc] initWithCapacity: 10];
}
- (void)dealloc
@ -765,15 +762,9 @@ static NSArray *XmlBoolDefaultYes = nil;
RELEASE(_orderedObjects);
RELEASE(_orderedObjectsDict);
RELEASE(_resources);
RELEASE(_customClasses);
[super dealloc];
}
- (NSMutableArray *) customClasses
{
return _customClasses;
}
- (void) createCustomClassRecordForId: (NSString *)theId
withParentClass: (NSString *)parentClassName
forCustomClass: (NSString *)customClassName

View file

@ -83,6 +83,28 @@
return AUTORELEASE(unarchiver);
}
- (NSString *) _substituteClassForClassName: (NSString *)className
{
NSString *result = className;
NSEnumerator *en = [_customClasses objectEnumerator];
NSDictionary *dict = nil;
// NSLog(@"_customClasses = %@", _customClasses);
while ((dict = [en nextObject]) != nil)
{
NSString *customClassName = [dict objectForKey: @"customClassName"];
if ([customClassName isEqualToString: className])
{
result = [dict objectForKey: @"parentClassName"];
break;
}
}
NSDebugLog(@"result = %@", result);
return result;
}
- (NSData *) _preProcessXib: (NSData *)data
{
NSData *result = data;
@ -143,8 +165,46 @@
id key = [[xmlKeys objectAtIndex:index] stringValue];
if ([key rangeOfString:@"CustomClassName"].location != NSNotFound)
{
// NSString *obj = [[xmlObjs objectAtIndex:index] stringValue];
[customClassDict setObject:[[xmlObjs objectAtIndex:index] stringValue] forKey:key];
NSString *cn = [[xmlObjs objectAtIndex: index] stringValue]; // className
[customClassDict setObject:cn forKey:key];
//
// If we are in IB/Gorm build the custom classes map so that we don't instantiate
// classes which don't exist (yet) in IB/Gorm. This allows editing of the model
// in IB/Gorm. If we are in the live app, don't bother as it's a waste of memory.
//
if ([NSClassSwapper isInInterfaceBuilder] == YES)
{
NSString *xpath = [NSString stringWithFormat: @"//object[@class=\"IBClassDescriber\"]"
@"//string[@key=\"className\"][text()=\"%@\"]"
@"/../string[@key=\"superclassName\"]", cn];
NSArray *descriptionObjs = [document nodesForXPath: xpath error: NULL];
if ([descriptionObjs count] > 0)
{
NSUInteger idx = [key rangeOfString: @"."].location;
if (idx != NSNotFound) // unlikely to be NSNotFound...
{
NSString *num = [key substringToIndex: idx];
NSXMLNode *descriptionNode = [descriptionObjs objectAtIndex: 0];
NSString *sc = [descriptionNode stringValue]; // superclassName
NSString *refXPath = [NSString stringWithFormat:
@"//object[@class=\"IBMutableOrderedSet\"][@key=\"objectRecords\"]"
@"/object/object[@class=\"IBObjectRecord\"]/int[@key=\"objectID\"]"
@"[text()=\"%@\"]/../reference[@key=\"object\"]/@ref", num];
NSArray *refNodes = [document nodesForXPath: refXPath error: NULL];
if ([refNodes count] > 0)
{
NSXMLElement *refNode = [refNodes objectAtIndex: 0];
NSString *refId = [refNode stringValue];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
refId, @"id", sc, @"parentClassName", cn, @"customClassName", nil];
[_customClasses addObject: dict];
}
}
}
}
}
}
}
@ -206,14 +266,16 @@
// If we are in the interface builder app, do not replace
// the existing classes with their custom subclasses.
if ([NSClassSwapper isInInterfaceBuilder] == NO)
NSString *clsName = className;
if ([NSClassSwapper isInInterfaceBuilder] == YES)
{
cls = NSClassFromString(className);
clsName = [self _substituteClassForClassName: className];
}
cls = NSClassFromString(clsName);
classNode = [classNodes objectAtIndex:0];
classAttr = [classNode attributeForName:@"class"];
[classAttr setStringValue:className];
[classAttr setStringValue: className];
if (cls != nil)
{
@ -232,7 +294,7 @@
id cellAttr = nil;
cellNode = [cellNodes objectAtIndex:0];
cellAttr = [cellNode attributeForName:@"class"];
[cellAttr setStringValue:cellClassString];
[cellAttr setStringValue: cellClassString];
}
}
}
@ -264,6 +326,9 @@
NSXMLParser *theParser;
NSData *theData = data;
// Dictionary which contains custom class information for Gorm/IB.
_customClasses = [[NSMutableArray alloc] initWithCapacity: 10];
theData = [self _preProcessXib: data];
if (theData == nil)
{
@ -298,6 +363,7 @@
DESTROY(objects);
DESTROY(stack);
DESTROY(decoded);
DESTROY(_customClasses);
[super dealloc];
}
@ -364,11 +430,17 @@ didStartElement: (NSString*)elementName
}
}
- (id) allocObjectForClassName: (NSString*)classname
- (id) allocObjectForClassName: (NSString*)clsname
{
Class c = nil;
id delegate = [self delegate];
NSString *classname = clsname;
if ([NSClassSwapper isInInterfaceBuilder] == YES)
{
classname = [self _substituteClassForClassName: classname];
}
c = [self classForClassName: classname];
if (c == nil)
@ -1033,4 +1105,10 @@ didStartElement: (NSString*)elementName
{
return decoded;
}
- (NSArray *) customClasses
{
return _customClasses;
}
@end