├── Classes ├── RootViewController.h ├── TreeListTableViewCell.h ├── TreeListAppDelegate.h ├── TreeListModel.h ├── TreeListAppDelegate.m ├── RootViewController.m ├── TreeListModel.m └── TreeListTableViewCell.m ├── main.m ├── TreeList_Prefix.pch ├── TreeList-Info.plist ├── NSString+SBJSON.m ├── NSObject+SBJSON.m ├── NSString+SBJSON.h ├── NSObject+SBJSON.h ├── JSON.h ├── SBJsonBase.m ├── SBJsonBase.h ├── SBJsonParser.h ├── contents.json ├── SBJsonWriter.h ├── README.md ├── SBJsonWriter.m ├── SBJsonParser.m ├── TreeList.xcodeproj └── project.pbxproj ├── RootViewController.xib ├── MainWindow.xib └── Resources-iPad └── MainWindow-iPad.xib /Classes/RootViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.h 3 | // TreeList 4 | // 5 | // Created by Stephan Eletzhofer on 06.05.11. 6 | // Copyright 2011 Nexiles GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "TreeListModel.h" 12 | 13 | @interface RootViewController : UITableViewController { 14 | } 15 | 16 | @property (nonatomic, retain) TreeListModel *model; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TreeList 4 | // 5 | // Created by Stephan Eletzhofer on 06.05.11. 6 | // Copyright 2011 Nexiles GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) { 12 | 13 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 14 | int retVal = UIApplicationMain(argc, argv, nil, nil); 15 | [pool release]; 16 | return retVal; 17 | } 18 | -------------------------------------------------------------------------------- /Classes/TreeListTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // TreeListTableViewCell.h 3 | // TreeList 4 | // 5 | // Created by Stephan Eletzhofer on 09.05.11. 6 | // Copyright 2011 Nexiles GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface TreeListTableViewCell : UITableViewCell { 13 | 14 | } 15 | 16 | @property (nonatomic, assign) BOOL isOpen; 17 | @property (nonatomic, assign) BOOL hasChildren; 18 | 19 | @property (nonatomic, retain) NSString *name; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /Classes/TreeListAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // TreeListAppDelegate.h 3 | // TreeList 4 | // 5 | // Created by Stephan Eletzhofer on 06.05.11. 6 | // Copyright 2011 Nexiles GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TreeListAppDelegate : NSObject { 12 | 13 | UIWindow *window; 14 | UINavigationController *navigationController; 15 | } 16 | 17 | @property (nonatomic, retain) IBOutlet UIWindow *window; 18 | @property (nonatomic, retain) IBOutlet UINavigationController *navigationController; 19 | 20 | @end 21 | 22 | -------------------------------------------------------------------------------- /TreeList_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'TreeList' target in the 'TreeList' project 3 | // 4 | #import 5 | 6 | #ifndef __IPHONE_3_0 7 | #warning "This project uses features only available in iPhone SDK 3.0 and later." 8 | #endif 9 | 10 | #ifdef DEBUG 11 | # define DBGS if (dbg>0) NSLog(@"%s START", __func__) 12 | # define DBG(fmt, ...) if (dbg>0) NSLog(@"%s: " fmt, __func__, ##__VA_ARGS__) 13 | # define DBGX(lvl, fmt, ...) if (dbg>=lvl) NSLog(@"%s: " fmt, __func__, ##__VA_ARGS__) 14 | #else 15 | # define DBGS do { } while (0) 16 | # define DBG(...) do {} while (0) 17 | # define DBGX(...) do {} while (0) 18 | #endif 19 | 20 | 21 | #ifdef __OBJC__ 22 | #import 23 | #import 24 | #endif 25 | -------------------------------------------------------------------------------- /TreeList-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | com.nexiles.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 0.3 25 | LSRequiresIPhoneOS 26 | 27 | NSMainNibFile 28 | MainWindow 29 | NSMainNibFile~ipad 30 | MainWindow-iPad 31 | 32 | 33 | -------------------------------------------------------------------------------- /Classes/TreeListModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // TreeListModel.h 3 | // TreeList 4 | // 5 | // Created by Stephan Eletzhofer on 09.05.11. 6 | // Copyright 2011 Nexiles GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TreeListModel : NSObject { 12 | NSInteger cell_count; 13 | 14 | } 15 | 16 | @property (nonatomic, retain) id root; 17 | @property (nonatomic, readonly) NSInteger cellCount; 18 | 19 | 20 | // key paths for accessing the model object 21 | @property (nonatomic, retain) NSString *isOpenKeyPath; 22 | @property (nonatomic, retain) NSString *keyKeyPath; 23 | @property (nonatomic, retain) NSString *childKeyPath; 24 | 25 | // designated initializer 26 | -(id)init; 27 | -(id)initWithDictionary:(NSMutableDictionary *)dict; 28 | -(id)initWithJSONString:(NSString *)jsonString; 29 | -(id)initWithJSONFilePath:(NSString *)filePath; 30 | 31 | // item and item level access 32 | -(id)itemForRowAtIndexPath:(NSIndexPath *)indexPath; 33 | -(NSInteger)levelForRowAtIndexPath:(NSIndexPath *)indexPath; 34 | 35 | // open/close state 36 | -(BOOL)isCellOpenForRowAtIndexPath:(NSIndexPath *)indexPath; 37 | -(void)setOpenClose:(BOOL)state forRowAtIndexPath:(NSIndexPath *)indexPath; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /NSString+SBJSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2007-2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "NSString+SBJSON.h" 31 | #import "SBJsonParser.h" 32 | 33 | @implementation NSString (NSString_SBJSON) 34 | 35 | - (id)JSONValue 36 | { 37 | SBJsonParser *jsonParser = [SBJsonParser new]; 38 | id repr = [jsonParser objectWithString:self]; 39 | if (!repr) 40 | NSLog(@"-JSONValue failed. Error trace is: %@", [jsonParser errorTrace]); 41 | [jsonParser release]; 42 | return repr; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /NSObject+SBJSON.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "NSObject+SBJSON.h" 31 | #import "SBJsonWriter.h" 32 | 33 | @implementation NSObject (NSObject_SBJSON) 34 | 35 | - (NSString *)JSONRepresentation { 36 | SBJsonWriter *jsonWriter = [SBJsonWriter new]; 37 | NSString *json = [jsonWriter stringWithObject:self]; 38 | if (!json) 39 | NSLog(@"-JSONRepresentation failed. Error trace is: %@", [jsonWriter errorTrace]); 40 | [jsonWriter release]; 41 | return json; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /NSString+SBJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | 32 | /** 33 | @brief Adds JSON parsing methods to NSString 34 | 35 | This is a category on NSString that adds methods for parsing the target string. 36 | */ 37 | @interface NSString (NSString_SBJSON) 38 | 39 | /** 40 | @brief Returns the NSDictionary or NSArray represented by the current string's JSON representation. 41 | 42 | Returns the dictionary or array represented in the receiver, or nil on error. 43 | 44 | Returns the NSDictionary or NSArray represented by the current string's JSON representation. 45 | */ 46 | - (id)JSONValue; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /NSObject+SBJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | 32 | 33 | /** 34 | @brief Adds JSON generation to Foundation classes 35 | 36 | This is a category on NSObject that adds methods for returning JSON representations 37 | of standard objects to the objects themselves. This means you can call the 38 | -JSONRepresentation method on an NSArray object and it'll do what you want. 39 | */ 40 | @interface NSObject (NSObject_SBJSON) 41 | 42 | /** 43 | @brief Returns a string containing the receiver encoded in JSON. 44 | 45 | This method is added as a category on NSObject but is only actually 46 | supported for the following objects: 47 | @li NSDictionary 48 | @li NSArray 49 | */ 50 | - (NSString *)JSONRepresentation; 51 | 52 | @end 53 | 54 | -------------------------------------------------------------------------------- /JSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009-2010 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | /** 31 | @mainpage A strict JSON parser and generator for Objective-C 32 | 33 | JSON (JavaScript Object Notation) is a lightweight data-interchange 34 | format. This framework provides two apis for parsing and generating 35 | JSON. One standard object-based and a higher level api consisting of 36 | categories added to existing Objective-C classes. 37 | 38 | This framework does its best to be as strict as possible, both in what it accepts and what it generates. For example, it does not support trailing commas in arrays or objects. Nor does it support embedded comments, or anything else not in the JSON specification. This is considered a feature. 39 | 40 | @section Links 41 | 42 | @li Project home page. 43 | @li Online version of the API documentation. 44 | 45 | */ 46 | 47 | 48 | // This setting of 1 is best if you copy the source into your project. 49 | // The build transforms the 1 to a 0 when building the framework and static lib. 50 | 51 | #if 1 52 | 53 | #import "SBJsonParser.h" 54 | #import "SBJsonWriter.h" 55 | #import "NSObject+SBJSON.h" 56 | #import "NSString+SBJSON.h" 57 | 58 | #else 59 | 60 | #import 61 | #import 62 | #import 63 | #import 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /SBJsonBase.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJsonBase.h" 31 | NSString * SBJSONErrorDomain = @"org.brautaset.JSON.ErrorDomain"; 32 | 33 | 34 | @implementation SBJsonBase 35 | 36 | @synthesize errorTrace; 37 | @synthesize maxDepth; 38 | 39 | - (id)init { 40 | self = [super init]; 41 | if (self) 42 | self.maxDepth = 512; 43 | return self; 44 | } 45 | 46 | - (void)dealloc { 47 | [errorTrace release]; 48 | [super dealloc]; 49 | } 50 | 51 | - (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str { 52 | NSDictionary *userInfo; 53 | if (!errorTrace) { 54 | errorTrace = [NSMutableArray new]; 55 | userInfo = [NSDictionary dictionaryWithObject:str forKey:NSLocalizedDescriptionKey]; 56 | 57 | } else { 58 | userInfo = [NSDictionary dictionaryWithObjectsAndKeys: 59 | str, NSLocalizedDescriptionKey, 60 | [errorTrace lastObject], NSUnderlyingErrorKey, 61 | nil]; 62 | } 63 | 64 | NSError *error = [NSError errorWithDomain:SBJSONErrorDomain code:code userInfo:userInfo]; 65 | 66 | [self willChangeValueForKey:@"errorTrace"]; 67 | [errorTrace addObject:error]; 68 | [self didChangeValueForKey:@"errorTrace"]; 69 | } 70 | 71 | - (void)clearErrorTrace { 72 | [self willChangeValueForKey:@"errorTrace"]; 73 | [errorTrace release]; 74 | errorTrace = nil; 75 | [self didChangeValueForKey:@"errorTrace"]; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /Classes/TreeListAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // TreeListAppDelegate.m 3 | // TreeList 4 | // 5 | // Created by Stephan Eletzhofer on 06.05.11. 6 | // Copyright 2011 Nexiles GmbH. All rights reserved. 7 | // 8 | 9 | #import "TreeListAppDelegate.h" 10 | #import "RootViewController.h" 11 | 12 | 13 | @implementation TreeListAppDelegate 14 | 15 | @synthesize window; 16 | @synthesize navigationController; 17 | 18 | 19 | #pragma mark - 20 | #pragma mark Application lifecycle 21 | 22 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 23 | 24 | // Override point for customization after application launch. 25 | 26 | // Set the navigation controller as the window's root view controller and display. 27 | self.window.rootViewController = self.navigationController; 28 | [self.window makeKeyAndVisible]; 29 | 30 | return YES; 31 | } 32 | 33 | 34 | - (void)applicationWillResignActive:(UIApplication *)application { 35 | /* 36 | Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 37 | Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 38 | */ 39 | } 40 | 41 | 42 | - (void)applicationDidEnterBackground:(UIApplication *)application { 43 | /* 44 | Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 45 | If your application supports background execution, called instead of applicationWillTerminate: when the user quits. 46 | */ 47 | } 48 | 49 | 50 | - (void)applicationWillEnterForeground:(UIApplication *)application { 51 | /* 52 | Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background. 53 | */ 54 | } 55 | 56 | 57 | - (void)applicationDidBecomeActive:(UIApplication *)application { 58 | /* 59 | Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 60 | */ 61 | } 62 | 63 | 64 | - (void)applicationWillTerminate:(UIApplication *)application { 65 | /* 66 | Called when the application is about to terminate. 67 | See also applicationDidEnterBackground:. 68 | */ 69 | } 70 | 71 | 72 | #pragma mark - 73 | #pragma mark Memory management 74 | 75 | - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { 76 | /* 77 | Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. 78 | */ 79 | } 80 | 81 | 82 | - (void)dealloc { 83 | [navigationController release]; 84 | [window release]; 85 | [super dealloc]; 86 | } 87 | 88 | 89 | @end 90 | 91 | -------------------------------------------------------------------------------- /SBJsonBase.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | 32 | extern NSString * SBJSONErrorDomain; 33 | 34 | 35 | enum { 36 | EUNSUPPORTED = 1, 37 | EPARSENUM, 38 | EPARSE, 39 | EFRAGMENT, 40 | ECTRL, 41 | EUNICODE, 42 | EDEPTH, 43 | EESCAPE, 44 | ETRAILCOMMA, 45 | ETRAILGARBAGE, 46 | EEOF, 47 | EINPUT 48 | }; 49 | 50 | /** 51 | @brief Common base class for parsing & writing. 52 | 53 | This class contains the common error-handling code and option between the parser/writer. 54 | */ 55 | @interface SBJsonBase : NSObject { 56 | NSMutableArray *errorTrace; 57 | 58 | @protected 59 | NSUInteger depth, maxDepth; 60 | } 61 | 62 | /** 63 | @brief The maximum recursing depth. 64 | 65 | Defaults to 512. If the input is nested deeper than this the input will be deemed to be 66 | malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can 67 | turn off this security feature by setting the maxDepth value to 0. 68 | */ 69 | @property NSUInteger maxDepth; 70 | 71 | /** 72 | @brief Return an error trace, or nil if there was no errors. 73 | 74 | Note that this method returns the trace of the last method that failed. 75 | You need to check the return value of the call you're making to figure out 76 | if the call actually failed, before you know call this method. 77 | */ 78 | @property(copy,readonly) NSArray* errorTrace; 79 | 80 | /// @internal for use in subclasses to add errors to the stack trace 81 | - (void)addErrorWithCode:(NSUInteger)code description:(NSString*)str; 82 | 83 | /// @internal for use in subclasess to clear the error before a new parsing attempt 84 | - (void)clearErrorTrace; 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /SBJsonParser.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | #import "SBJsonBase.h" 32 | 33 | /** 34 | @brief The JSON parser class. 35 | 36 | JSON is mapped to Objective-C types in the following way: 37 | 38 | @li Null -> NSNull 39 | @li String -> NSMutableString 40 | @li Array -> NSMutableArray 41 | @li Object -> NSMutableDictionary 42 | @li Boolean -> NSNumber (initialised with -initWithBool:) 43 | @li Number -> (NSNumber | NSDecimalNumber) 44 | 45 | Since Objective-C doesn't have a dedicated class for boolean values, these turns into NSNumber 46 | instances. These are initialised with the -initWithBool: method, and 47 | round-trip back to JSON properly. (They won't silently suddenly become 0 or 1; they'll be 48 | represented as 'true' and 'false' again.) 49 | 50 | As an optimisation short JSON integers turn into NSNumber instances, while complex ones turn into NSDecimalNumber instances. 51 | We can thus avoid any loss of precision as JSON allows ridiculously large numbers. 52 | 53 | */ 54 | @interface SBJsonParser : SBJsonBase { 55 | 56 | @private 57 | const char *c; 58 | } 59 | 60 | /** 61 | @brief Return the object represented by the given string 62 | 63 | Returns the object represented by the passed-in string or nil on error. The returned object can be 64 | a string, number, boolean, null, array or dictionary. 65 | 66 | @param repr the json string to parse 67 | */ 68 | - (id)objectWithString:(NSString *)repr; 69 | 70 | /** 71 | @brief Return the object represented by the given string 72 | 73 | Returns the object represented by the passed-in string or nil on error. The returned object can be 74 | a string, number, boolean, null, array or dictionary. 75 | 76 | @param jsonText the json string to parse 77 | @param error pointer to an NSError object to populate on error 78 | */ 79 | 80 | - (id)objectWithString:(NSString*)jsonText 81 | error:(NSError**)error; 82 | 83 | 84 | @end 85 | 86 | 87 | -------------------------------------------------------------------------------- /Classes/RootViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.m 3 | // TreeList 4 | // 5 | // Created by Stephan Eletzhofer on 06.05.11. 6 | // Copyright 2011 Nexiles GmbH. All rights reserved. 7 | // 8 | 9 | #import "NSString+SBJSON.h" 10 | #import "TreeListTableViewCell.h" 11 | #import "RootViewController.h" 12 | 13 | static int dbg = 0; 14 | @implementation RootViewController 15 | 16 | 17 | @synthesize model; 18 | 19 | #pragma mark - 20 | #pragma mark View lifecycle 21 | 22 | - (void)viewDidLoad 23 | { 24 | DBGS; 25 | [super viewDidLoad]; 26 | NSString *filePath = [[NSBundle mainBundle] pathForResource:@"contents" ofType:@"json"]; 27 | 28 | self.model = [[TreeListModel alloc] initWithJSONFilePath:filePath]; 29 | } 30 | 31 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 32 | return YES; 33 | } 34 | 35 | #pragma mark - 36 | #pragma mark Table view data source 37 | 38 | // Customize the number of sections in the table view. 39 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 40 | DBGS; 41 | return 1; 42 | } 43 | 44 | // Customize the number of rows in the table view. 45 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 46 | { 47 | DBGS; 48 | return self.model.cellCount; 49 | } 50 | 51 | 52 | // Customize the appearance of table view cells. 53 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 54 | 55 | DBG(@"indexPath=%@", indexPath); 56 | 57 | static NSString *CellIdentifier = @"Cell"; 58 | 59 | TreeListTableViewCell *cell = (TreeListTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 60 | if (cell == nil) { 61 | cell = [[[TreeListTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; 62 | } 63 | 64 | NSMutableDictionary *item = [self.model itemForRowAtIndexPath:indexPath]; 65 | 66 | cell.indentationLevel = [self.model levelForRowAtIndexPath:indexPath]; 67 | cell.name = [NSString stringWithFormat:@"%@", [item objectForKey:@"key"]]; 68 | 69 | BOOL isOpen = [self.model isCellOpenForRowAtIndexPath:indexPath]; 70 | cell.isOpen = isOpen; 71 | int item_count = [[item valueForKeyPath:@"value.@count"] intValue]; 72 | cell.hasChildren = item_count > 0; 73 | if (isOpen == NO && item_count > 0) { 74 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 75 | } else { 76 | cell.accessoryType = UITableViewCellAccessoryNone; 77 | } 78 | 79 | [cell setNeedsDisplay]; 80 | return cell; 81 | } 82 | 83 | #pragma mark - 84 | #pragma mark Table view delegate 85 | 86 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 87 | { 88 | DBG(@"indexPath=%@", indexPath); 89 | 90 | NSMutableDictionary *item = [self.model itemForRowAtIndexPath:indexPath]; 91 | int item_count = [[item valueForKeyPath:@"value.@count"] intValue]; 92 | if (item_count<=0) 93 | return; 94 | 95 | BOOL newState = NO; 96 | BOOL isOpen = [self.model isCellOpenForRowAtIndexPath:indexPath]; 97 | if (NO == isOpen) { 98 | newState = YES; 99 | } else { 100 | newState = NO; 101 | } 102 | [self.model setOpenClose:newState forRowAtIndexPath:indexPath]; 103 | 104 | [tableView beginUpdates]; 105 | [tableView reloadSections:[NSIndexSet indexSetWithIndex:0] 106 | withRowAnimation:UITableViewRowAnimationFade]; 107 | [tableView endUpdates]; 108 | } 109 | 110 | 111 | #pragma mark - 112 | #pragma mark Memory management 113 | 114 | - (void)dealloc 115 | { 116 | DBGS; 117 | self.model = nil; 118 | [super dealloc]; 119 | } 120 | 121 | 122 | @end 123 | // vim: set sw=4 ts=4 expandta: 124 | -------------------------------------------------------------------------------- /contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "isOpen": true, 3 | "key": "root", 4 | "line_number": 10, 5 | "quantity": 3, 6 | "value": [ 7 | { 8 | "isOpen": true, 9 | "key": "Chapter 1", 10 | "line_number": 20, 11 | "quantity": 3, 12 | "value": [ 13 | { 14 | "isOpen": false, 15 | "key": "Subchapter 1.1", 16 | "line_number": 30, 17 | "quantity": 3, 18 | "value": [] 19 | }, 20 | { 21 | "isOpen": true, 22 | "key": "Subchapter 1.2", 23 | "line_number": 40, 24 | "quantity": 3, 25 | "value": [ 26 | { 27 | "isOpen": false, 28 | "key": "Sub Sub Chapter 1.2.1", 29 | "line_number": 50, 30 | "quantity": 3, 31 | "value": [] 32 | }, 33 | { 34 | "isOpen": false, 35 | "key": "Sub Sub Chapter 1.2.2", 36 | "line_number": 60, 37 | "quantity": 3, 38 | "value": [] 39 | }, 40 | { 41 | "isOpen": false, 42 | "key": "Sub Sub Chapter 1.2.3", 43 | "line_number": 70, 44 | "quantity": 3, 45 | "value": [] 46 | } 47 | ] 48 | }, 49 | { 50 | "isOpen": false, 51 | "key": "Subchapter 1.3", 52 | "line_number": 80, 53 | "quantity": 3, 54 | "value": [] 55 | } 56 | ] 57 | }, 58 | { 59 | "isOpen": false, 60 | "key": "Chapter 2", 61 | "line_number": 90, 62 | "quantity": 3, 63 | "value": [ 64 | { 65 | "isOpen": false, 66 | "key": "Subchapter 2.1", 67 | "line_number": 100, 68 | "quantity": 3, 69 | "value": [] 70 | }, 71 | { 72 | "isOpen": false, 73 | "key": "Subchapter 2.2", 74 | "line_number": 110, 75 | "quantity": 3, 76 | "value": [] 77 | }, 78 | { 79 | "isOpen": false, 80 | "key": "Subchapter 2.3", 81 | "line_number": 120, 82 | "quantity": 3, 83 | "value": [] 84 | } 85 | ] 86 | }, 87 | { 88 | "isOpen": true, 89 | "key": "Chapter 3", 90 | "line_number": 130, 91 | "quantity": 3, 92 | "value": [ 93 | { 94 | "isOpen": false, 95 | "key": "Subchapter 3.1", 96 | "line_number": 140, 97 | "quantity": 3, 98 | "value": [] 99 | }, 100 | { 101 | "isOpen": false, 102 | "key": "Subchapter 3.2", 103 | "line_number": 150, 104 | "quantity": 3, 105 | "value": [] 106 | }, 107 | { 108 | "isOpen": false, 109 | "key": "Subchapter 3.3", 110 | "line_number": 160, 111 | "quantity": 3, 112 | "value": [] 113 | } 114 | ] 115 | } 116 | ] 117 | } 118 | -------------------------------------------------------------------------------- /SBJsonWriter.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import 31 | #import "SBJsonBase.h" 32 | 33 | /** 34 | @brief The JSON writer class. 35 | 36 | Objective-C types are mapped to JSON types in the following way: 37 | 38 | @li NSNull -> Null 39 | @li NSString -> String 40 | @li NSArray -> Array 41 | @li NSDictionary -> Object 42 | @li NSNumber (-initWithBool:) -> Boolean 43 | @li NSNumber -> Number 44 | 45 | In JSON the keys of an object must be strings. NSDictionary keys need 46 | not be, but attempting to convert an NSDictionary with non-string keys 47 | into JSON will throw an exception. 48 | 49 | NSNumber instances created with the +initWithBool: method are 50 | converted into the JSON boolean "true" and "false" values, and vice 51 | versa. Any other NSNumber instances are converted to a JSON number the 52 | way you would expect. 53 | 54 | */ 55 | @interface SBJsonWriter : SBJsonBase { 56 | 57 | @private 58 | BOOL sortKeys, humanReadable; 59 | } 60 | 61 | /** 62 | @brief Whether we are generating human-readable (multiline) JSON. 63 | 64 | Set whether or not to generate human-readable JSON. The default is NO, which produces 65 | JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable 66 | JSON with linebreaks after each array value and dictionary key/value pair, indented two 67 | spaces per nesting level. 68 | */ 69 | @property BOOL humanReadable; 70 | 71 | /** 72 | @brief Whether or not to sort the dictionary keys in the output. 73 | 74 | If this is set to YES, the dictionary keys in the JSON output will be in sorted order. 75 | (This is useful if you need to compare two structures, for example.) The default is NO. 76 | */ 77 | @property BOOL sortKeys; 78 | 79 | /** 80 | @brief Return JSON representation (or fragment) for the given object. 81 | 82 | Returns a string containing JSON representation of the passed in value, or nil on error. 83 | If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. 84 | 85 | @param value any instance that can be represented as a JSON fragment 86 | 87 | */ 88 | - (NSString*)stringWithObject:(id)value; 89 | 90 | /** 91 | @brief Return JSON representation (or fragment) for the given object. 92 | 93 | Returns a string containing JSON representation of the passed in value, or nil on error. 94 | If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. 95 | 96 | @param value any instance that can be represented as a JSON fragment 97 | @param error pointer to object to be populated with NSError on failure 98 | 99 | */- (NSString*)stringWithObject:(id)value 100 | error:(NSError**)error; 101 | 102 | 103 | @end 104 | 105 | /** 106 | @brief Allows generation of JSON for otherwise unsupported classes. 107 | 108 | If you have a custom class that you want to create a JSON representation for you can implement 109 | this method in your class. It should return a representation of your object defined 110 | in terms of objects that can be translated into JSON. For example, a Person 111 | object might implement it like this: 112 | 113 | @code 114 | - (id)proxyForJson { 115 | return [NSDictionary dictionaryWithObjectsAndKeys: 116 | name, @"name", 117 | phone, @"phone", 118 | email, @"email", 119 | nil]; 120 | } 121 | @endcode 122 | 123 | */ 124 | @interface NSObject (SBProxyForJson) 125 | - (id)proxyForJson; 126 | @end 127 | 128 | -------------------------------------------------------------------------------- /Classes/TreeListModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // TreeListModel.m 3 | // TreeList 4 | // 5 | // Created by Stephan Eletzhofer on 09.05.11. 6 | // Copyright 2011 Nexiles GmbH. All rights reserved. 7 | // 8 | 9 | #import "TreeListModel.h" 10 | #import "NSString+SBJSON.h" 11 | 12 | static int dbg = 0; 13 | 14 | @interface TreeListModel () 15 | 16 | @property (nonatomic, retain) NSMutableArray *lookup; 17 | @property (nonatomic, retain) NSMutableArray *level; 18 | 19 | -(void)recalculate; 20 | -(int)recalculateWithItem:(id)item andLevel:(int)lvl; 21 | 22 | @end 23 | 24 | @implementation TreeListModel 25 | 26 | @synthesize cellCount; 27 | @synthesize root; 28 | @synthesize level; 29 | @synthesize lookup; 30 | 31 | @synthesize keyKeyPath; 32 | @synthesize childKeyPath; 33 | @synthesize isOpenKeyPath; 34 | 35 | #pragma mark - 36 | #pragma mark accessors 37 | 38 | -(NSInteger)cellCount 39 | { 40 | return cell_count; 41 | } 42 | 43 | 44 | -(void)setRoot:(id)newRoot; 45 | { 46 | DBG(@"newRoot=%@", newRoot); 47 | @synchronized (self) { 48 | if (root != newRoot) { 49 | [root release]; 50 | root = nil; 51 | if (newRoot) { 52 | root = [newRoot retain]; 53 | [self recalculate]; 54 | } 55 | } 56 | } 57 | } 58 | 59 | #pragma mark - 60 | #pragma mark model item data access 61 | 62 | -(id)itemForRowAtIndexPath:(NSIndexPath *)indexPath 63 | { 64 | DBG(@"indexPath=%@", indexPath); 65 | return [self.lookup objectAtIndex:indexPath.row+1]; 66 | } 67 | 68 | -(NSInteger)levelForRowAtIndexPath:(NSIndexPath *)indexPath 69 | { 70 | DBG(@"indexPath=%@", indexPath); 71 | return [[self.level objectAtIndex:indexPath.row+1] intValue] - 1; 72 | } 73 | 74 | -(BOOL)isCellOpenForRowAtIndexPath:(NSIndexPath *)indexPath 75 | { 76 | DBG(@"indexPath=%@", indexPath); 77 | id item = [self itemForRowAtIndexPath:indexPath]; 78 | return [[item valueForKeyPath:self.isOpenKeyPath] boolValue]; 79 | } 80 | 81 | -(void)setOpenClose:(BOOL)state forRowAtIndexPath:(NSIndexPath *)indexPath 82 | { 83 | DBG(@"state=%d", state); 84 | id item = [self itemForRowAtIndexPath:indexPath]; 85 | [item setValue:[NSNumber numberWithBool:state] forKey:self.isOpenKeyPath]; 86 | [self recalculate]; 87 | } 88 | 89 | #pragma mark - 90 | #pragma mark internal model housekeeping 91 | 92 | -(void)recalculate 93 | { 94 | DBGS; 95 | self.lookup = [NSMutableArray array]; 96 | self.level = [NSMutableArray array]; 97 | cell_count = [self recalculateWithItem:self.root 98 | andLevel:0] - 1; 99 | #ifdef DEBUG 100 | for (id item in self.lookup) { 101 | DBG(@"item.key=%@", [item valueForKeyPath:self.keyKeyPath]); 102 | 103 | } 104 | #endif 105 | DBG(@"cell_count=%d", cell_count); 106 | 107 | } 108 | 109 | -(int)recalculateWithItem:(id)item andLevel:(int)lvl; 110 | { 111 | DBG(@"item.key, isopen=%@, %@", [item valueForKeyPath:self.keyKeyPath], [item valueForKeyPath:self.isOpenKeyPath]); 112 | 113 | int count = 1; 114 | 115 | [self.lookup addObject: item]; 116 | [self.level addObject: [NSNumber numberWithInt:lvl]]; 117 | 118 | BOOL isOpen = [[item valueForKeyPath:self.isOpenKeyPath] boolValue]; 119 | 120 | if (isOpen) { 121 | for (id child in [item valueForKeyPath:self.childKeyPath]) { 122 | DBGX(2, @"count=%d, child.key=%@ child.isOpen=%@", 123 | count, 124 | [child valueForKeyPath:self.keyKeyPath], 125 | [child valueForKeyPath:self.isOpenKeyPath]); 126 | 127 | count += [self recalculateWithItem:child andLevel:lvl + 1]; 128 | } 129 | } 130 | 131 | DBGX(2, @"===> level %d: count=%d for item.key=%@", lvl, count, [item valueForKeyPath:self.keyKeyPath]); 132 | return count; 133 | } 134 | 135 | #pragma mark - 136 | #pragma mark init and dealloc 137 | 138 | -(id)init 139 | { 140 | self = [super init]; 141 | if (self) { 142 | // initialize key paths for model access 143 | self.keyKeyPath = @"key"; 144 | self.isOpenKeyPath = @"isOpen"; 145 | self.childKeyPath = @"value"; 146 | 147 | self.lookup = [NSMutableArray array]; 148 | self.level = [NSMutableArray array]; 149 | 150 | return self; 151 | } 152 | return nil; 153 | } 154 | 155 | -(id)initWithDictionary:(NSMutableDictionary *)dict 156 | { 157 | self = [self init]; 158 | if (self) { 159 | self.root = dict; 160 | return self; 161 | } 162 | return nil; 163 | } 164 | 165 | -(id)initWithJSONString:(NSString *)jsonString 166 | { 167 | return [self initWithDictionary:[jsonString JSONValue]]; 168 | } 169 | 170 | -(id)initWithJSONFilePath:(NSString *)filePath 171 | { 172 | DBG(@"filePath=%@", filePath); 173 | NSString *data = [NSString stringWithContentsOfFile:filePath 174 | encoding:NSUTF8StringEncoding 175 | error:nil]; 176 | return [self initWithJSONString:data]; 177 | } 178 | 179 | -(void)dealloc 180 | { 181 | self.root = nil; 182 | self.lookup = nil; 183 | self.level = nil; 184 | self.isOpenKeyPath = nil; 185 | self.keyKeyPath = nil; 186 | self.childKeyPath = nil; 187 | [super dealloc]; 188 | } 189 | 190 | 191 | @end 192 | // vim: set sw=4 ts=4 expandtab: 193 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ======================= 2 | Cocoa Tree View Example 3 | ======================= 4 | 5 | Author: Stefan Eletzhofer 6 | 7 | Date: 2011-06-30 8 | 9 | Version: 0.3.1 10 | 11 | 12 | Abstract 13 | ======== 14 | 15 | For a project I'm currently at, I have the requirement to view heirachical 16 | data in **one** UITableView. 17 | 18 | This is what I've come up with, it's a proof-of-concept and badly needs 19 | refactoring. 20 | 21 | 22 |
23 |
by MacBuildServer 24 |
25 | 26 | 27 | License 28 | ======= 29 | 30 | This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 31 | Unported License. To view a copy of this license, visit 32 | http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative 33 | Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, 34 | USA. 35 | 36 | Features 37 | ======== 38 | 39 | - collapsable/expandable UITableViewCells 40 | - NSMutableDictionary as data model 41 | - no hacks 42 | 43 | Data Model 44 | ========== 45 | 46 | All the specific tree/list handling stuff is done in `TreeListModel`. This 47 | class offers accessor methods which make it fairly simple to use it as a 48 | `UITableViewDataSource`. 49 | 50 | Demo data is load from a JSON file which looks like this. You get the 51 | idea ;) 52 | 53 | ```json 54 | { 55 | "key": "root", 56 | "isOpen": true, 57 | "value": [ 58 | { 59 | "isOpen": true, 60 | "key": "Chapter 1", 61 | "value": [ 62 | { 63 | "isOpen": false, 64 | "key": "Subchapter 1.1", 65 | "value": [] 66 | }, 67 | { 68 | "isOpen": true, 69 | "key": "Subchapter 1.2", 70 | "value": [ 71 | { 72 | "isOpen": false, 73 | "key": "Sub Sub Chapter 1.2.1", 74 | "value": [] 75 | }, 76 | { 77 | "isOpen": false, 78 | "key": "Sub Sub Chapter 1.2.2", 79 | "value": [] 80 | }, 81 | { 82 | "isOpen": false, 83 | "key": "Sub Sub Chapter 1.2.3", 84 | "value": [] 85 | } 86 | ] 87 | }, 88 | { 89 | "isOpen": false, 90 | "key": "Subchapter 1.3", 91 | "value": [] 92 | } 93 | ] 94 | }, 95 | { 96 | "isOpen": false, 97 | "key": "Chapter 2", 98 | "value": [ 99 | { 100 | "isOpen": false, 101 | "key": "Subchapter 2.1", 102 | "value": [] 103 | }, 104 | { 105 | "isOpen": false, 106 | "key": "Subchapter 2.2", 107 | "value": [] 108 | }, 109 | { 110 | "isOpen": false, 111 | "key": "Subchapter 2.3", 112 | "value": [] 113 | } 114 | ] 115 | }, 116 | { 117 | "isOpen": true, 118 | "key": "Chapter 3", 119 | "value": [ 120 | { 121 | "isOpen": false, 122 | "key": "Subchapter 3.1", 123 | "value": [] 124 | }, 125 | { 126 | "isOpen": false, 127 | "key": "Subchapter 3.2", 128 | "value": [] 129 | }, 130 | { 131 | "isOpen": false, 132 | "key": "Subchapter 3.3", 133 | "value": [] 134 | } 135 | ] 136 | } 137 | ] 138 | } 139 | ``` 140 | 141 | Changelog 142 | ========= 143 | 144 | 0.3.1 - 2011-06-30 145 | ------------------ 146 | 147 | - update license 148 | 149 | 0.3 - 2011-05-10 150 | ---------------- 151 | 152 | - added some custom UITableViewCells which fancy lines and stuff. 153 | - upgrade JSON data model to multivalued data. 154 | - made a universal app. 155 | - use KVC to access model items. Remove NSMutableDictionary 156 | dependency. 157 | 158 | 0.2 - 2011-05-09 159 | ---------------- 160 | 161 | - refactored, created `TreeListModel`. 162 | 163 | 0.1 - 2011-05-06 164 | ---------------- 165 | 166 | - Initial release to github 167 | 168 | -------------------------------------------------------------------------------- /SBJsonWriter.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJsonWriter.h" 31 | 32 | @interface SBJsonWriter () 33 | 34 | - (BOOL)appendValue:(id)fragment into:(NSMutableString*)json; 35 | - (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json; 36 | - (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json; 37 | - (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json; 38 | 39 | - (NSString*)indent; 40 | 41 | @end 42 | 43 | @implementation SBJsonWriter 44 | 45 | @synthesize sortKeys; 46 | @synthesize humanReadable; 47 | 48 | static NSMutableCharacterSet *kEscapeChars; 49 | 50 | + (void)initialize { 51 | kEscapeChars = [[NSMutableCharacterSet characterSetWithRange: NSMakeRange(0,32)] retain]; 52 | [kEscapeChars addCharactersInString: @"\"\\"]; 53 | } 54 | 55 | - (NSString*)stringWithObject:(id)value { 56 | [self clearErrorTrace]; 57 | 58 | if ([value isKindOfClass:[NSDictionary class]] || [value isKindOfClass:[NSArray class]]) { 59 | depth = 0; 60 | NSMutableString *json = [NSMutableString stringWithCapacity:128]; 61 | if ([self appendValue:value into:json]) 62 | return json; 63 | } 64 | 65 | if ([value respondsToSelector:@selector(proxyForJson)]) { 66 | NSString *tmp = [self stringWithObject:[value proxyForJson]]; 67 | if (tmp) 68 | return tmp; 69 | } 70 | 71 | [self addErrorWithCode:EFRAGMENT description:@"Not valid type for JSON"]; 72 | return nil; 73 | } 74 | 75 | - (NSString*)stringWithObject:(id)value error:(NSError**)error { 76 | NSString *tmp = [self stringWithObject:value]; 77 | if (tmp) 78 | return tmp; 79 | 80 | if (error) 81 | *error = [self.errorTrace lastObject]; 82 | return nil; 83 | } 84 | 85 | - (NSString*)indent { 86 | return [@"\n" stringByPaddingToLength:1 + 2 * depth withString:@" " startingAtIndex:0]; 87 | } 88 | 89 | - (BOOL)appendValue:(id)fragment into:(NSMutableString*)json { 90 | if ([fragment isKindOfClass:[NSDictionary class]]) { 91 | if (![self appendDictionary:fragment into:json]) 92 | return NO; 93 | 94 | } else if ([fragment isKindOfClass:[NSArray class]]) { 95 | if (![self appendArray:fragment into:json]) 96 | return NO; 97 | 98 | } else if ([fragment isKindOfClass:[NSString class]]) { 99 | if (![self appendString:fragment into:json]) 100 | return NO; 101 | 102 | } else if ([fragment isKindOfClass:[NSNumber class]]) { 103 | if ('c' == *[fragment objCType]) { 104 | [json appendString:[fragment boolValue] ? @"true" : @"false"]; 105 | } else if ([fragment isEqualToNumber:(NSNumber*)kCFNumberNaN]) { 106 | [self addErrorWithCode:EUNSUPPORTED description:@"NaN is not a valid number in JSON"]; 107 | return NO; 108 | 109 | } else if (isinf([fragment doubleValue])) { 110 | [self addErrorWithCode:EUNSUPPORTED description:@"Infinity is not a valid number in JSON"]; 111 | return NO; 112 | 113 | } else { 114 | [json appendString:[fragment stringValue]]; 115 | } 116 | } else if ([fragment isKindOfClass:[NSNull class]]) { 117 | [json appendString:@"null"]; 118 | } else if ([fragment respondsToSelector:@selector(proxyForJson)]) { 119 | [self appendValue:[fragment proxyForJson] into:json]; 120 | 121 | } else { 122 | [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"JSON serialisation not supported for %@", [fragment class]]]; 123 | return NO; 124 | } 125 | return YES; 126 | } 127 | 128 | - (BOOL)appendArray:(NSArray*)fragment into:(NSMutableString*)json { 129 | if (maxDepth && ++depth > maxDepth) { 130 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 131 | return NO; 132 | } 133 | [json appendString:@"["]; 134 | 135 | BOOL addComma = NO; 136 | for (id value in fragment) { 137 | if (addComma) 138 | [json appendString:@","]; 139 | else 140 | addComma = YES; 141 | 142 | if ([self humanReadable]) 143 | [json appendString:[self indent]]; 144 | 145 | if (![self appendValue:value into:json]) { 146 | return NO; 147 | } 148 | } 149 | 150 | depth--; 151 | if ([self humanReadable] && [fragment count]) 152 | [json appendString:[self indent]]; 153 | [json appendString:@"]"]; 154 | return YES; 155 | } 156 | 157 | - (BOOL)appendDictionary:(NSDictionary*)fragment into:(NSMutableString*)json { 158 | if (maxDepth && ++depth > maxDepth) { 159 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 160 | return NO; 161 | } 162 | [json appendString:@"{"]; 163 | 164 | NSString *colon = [self humanReadable] ? @" : " : @":"; 165 | BOOL addComma = NO; 166 | NSArray *keys = [fragment allKeys]; 167 | if (self.sortKeys) 168 | keys = [keys sortedArrayUsingSelector:@selector(compare:)]; 169 | 170 | for (id value in keys) { 171 | if (addComma) 172 | [json appendString:@","]; 173 | else 174 | addComma = YES; 175 | 176 | if ([self humanReadable]) 177 | [json appendString:[self indent]]; 178 | 179 | if (![value isKindOfClass:[NSString class]]) { 180 | [self addErrorWithCode:EUNSUPPORTED description: @"JSON object key must be string"]; 181 | return NO; 182 | } 183 | 184 | if (![self appendString:value into:json]) 185 | return NO; 186 | 187 | [json appendString:colon]; 188 | if (![self appendValue:[fragment objectForKey:value] into:json]) { 189 | [self addErrorWithCode:EUNSUPPORTED description:[NSString stringWithFormat:@"Unsupported value for key %@ in object", value]]; 190 | return NO; 191 | } 192 | } 193 | 194 | depth--; 195 | if ([self humanReadable] && [fragment count]) 196 | [json appendString:[self indent]]; 197 | [json appendString:@"}"]; 198 | return YES; 199 | } 200 | 201 | - (BOOL)appendString:(NSString*)fragment into:(NSMutableString*)json { 202 | 203 | [json appendString:@"\""]; 204 | 205 | NSRange esc = [fragment rangeOfCharacterFromSet:kEscapeChars]; 206 | if ( !esc.length ) { 207 | // No special chars -- can just add the raw string: 208 | [json appendString:fragment]; 209 | 210 | } else { 211 | NSUInteger length = [fragment length]; 212 | for (NSUInteger i = 0; i < length; i++) { 213 | unichar uc = [fragment characterAtIndex:i]; 214 | switch (uc) { 215 | case '"': [json appendString:@"\\\""]; break; 216 | case '\\': [json appendString:@"\\\\"]; break; 217 | case '\t': [json appendString:@"\\t"]; break; 218 | case '\n': [json appendString:@"\\n"]; break; 219 | case '\r': [json appendString:@"\\r"]; break; 220 | case '\b': [json appendString:@"\\b"]; break; 221 | case '\f': [json appendString:@"\\f"]; break; 222 | default: 223 | if (uc < 0x20) { 224 | [json appendFormat:@"\\u%04x", uc]; 225 | } else { 226 | CFStringAppendCharacters((CFMutableStringRef)json, &uc, 1); 227 | } 228 | break; 229 | 230 | } 231 | } 232 | } 233 | 234 | [json appendString:@"\""]; 235 | return YES; 236 | } 237 | 238 | 239 | @end 240 | -------------------------------------------------------------------------------- /Classes/TreeListTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // TreeListTableViewCell.m 3 | // TreeList 4 | // 5 | // Created by Stephan Eletzhofer on 09.05.11. 6 | // Copyright 2011 Nexiles GmbH. All rights reserved. 7 | // 8 | 9 | #import "TreeListTableViewCell.h" 10 | 11 | static int dbg = 0; 12 | 13 | #define MAX_LEVEL 3.0 14 | #define RADIUS (5.0) 15 | #define MARGIN_TOP (5.0) 16 | #define MARGIN_BOTTOM (5.0) 17 | #define MARGIN_LEFT (10.0) 18 | 19 | ////////////////////////////////////////////////////////////////////// 20 | ////////////////////////////////////////////////////////////////////// 21 | @interface IndentView : UIView 22 | { 23 | } 24 | 25 | @property (assign) int indentationLevel; 26 | @property (assign) CGFloat indentationWidth; 27 | @property (assign) BOOL hasChildren; 28 | @property (assign) BOOL isOpen; 29 | 30 | @property (nonatomic,retain) UILabel *nameLabel; 31 | @property (nonatomic,retain) UIImageView *imageView; 32 | 33 | - (id)initWithFrame:(CGRect)frame; 34 | 35 | @end 36 | 37 | @implementation IndentView 38 | 39 | @synthesize nameLabel; 40 | @synthesize imageView; 41 | 42 | @synthesize indentationLevel; 43 | @synthesize indentationWidth; 44 | @synthesize isOpen; 45 | @synthesize hasChildren; 46 | 47 | #pragma mark - 48 | #pragma mark custom drawing 49 | 50 | -(UIColor *)colorForLevel:(int)level 51 | { 52 | 53 | level = level>3?3:level; 54 | return [UIColor colorWithHue:98.0/360 55 | saturation:(level*0.2/MAX_LEVEL) 56 | brightness:0.95 57 | alpha:1.0]; 58 | } 59 | 60 | - (void) drawRect:(CGRect)rect 61 | { 62 | DBGS; 63 | [super drawRect:rect]; 64 | 65 | CGFloat height = self.frame.size.height; 66 | CGFloat width = self.frame.size.width; 67 | 68 | CGFloat indent = self.indentationLevel * self.indentationWidth; 69 | 70 | UIColor *strokeColor = [UIColor darkGrayColor]; 71 | 72 | DBG(@"height=%g", height); 73 | DBG(@"width=%g", width); 74 | DBG(@"indent=%g", indent); 75 | 76 | [self setBackgroundColor:[self colorForLevel:self.indentationLevel]]; 77 | 78 | CGContextRef context = UIGraphicsGetCurrentContext(); 79 | 80 | CGContextSaveGState(context); 81 | 82 | CGContextSetFillColorWithColor(context, [[self colorForLevel:self.indentationLevel] CGColor]); 83 | 84 | CGContextFillRect(context, self.frame); 85 | 86 | // name label 87 | CGRect nameLabelFrame = CGRectZero; 88 | nameLabelFrame.origin.x = indent + MARGIN_LEFT*2; 89 | nameLabelFrame.origin.y = MARGIN_TOP; 90 | nameLabelFrame.size.width = width/2; 91 | nameLabelFrame.size.height = height - MARGIN_TOP - MARGIN_BOTTOM; 92 | self.nameLabel.frame = nameLabelFrame; 93 | 94 | if (self.indentationLevel > 0) { 95 | for (int level = self.indentationLevel; level>0; level--) { 96 | CGContextSetFillColorWithColor(context, [[self colorForLevel:level - 1] CGColor]); 97 | CGFloat indent = (level - 1) * self.indentationWidth; 98 | CGContextBeginPath(context); 99 | 100 | CGContextMoveToPoint(context, 0, 0); 101 | CGContextAddLineToPoint(context, 0, height); // top right 102 | CGContextAddLineToPoint(context, indent + MARGIN_LEFT, height); // bottom right 103 | CGContextAddLineToPoint(context, indent + MARGIN_LEFT, 0); // bottom left 104 | 105 | 106 | CGContextClosePath(context); 107 | CGContextFillPath(context); 108 | CGContextStrokePath(context); 109 | 110 | 111 | // left hand border lines 112 | CGContextSetStrokeColorWithColor(context, [strokeColor CGColor]); 113 | CGContextBeginPath(context); 114 | CGContextMoveToPoint(context, indent + MARGIN_LEFT, height); // bottom right 115 | CGContextAddLineToPoint(context, indent + MARGIN_LEFT, 0); // bottom left 116 | CGContextStrokePath(context); 117 | 118 | 119 | } 120 | } 121 | 122 | if (self.hasChildren && self.isOpen) { 123 | CGContextSetFillColorWithColor(context, [[self colorForLevel:self.indentationLevel + 1] CGColor]); 124 | 125 | CGContextBeginPath(context); 126 | 127 | // bottom left 128 | CGContextMoveToPoint(context, indent + MARGIN_LEFT, height); 129 | CGContextAddArcToPoint(context, indent + MARGIN_LEFT, height - MARGIN_BOTTOM, 130 | width, height - MARGIN_BOTTOM, 131 | RADIUS); 132 | CGContextAddLineToPoint(context, width, height - MARGIN_BOTTOM); 133 | CGContextAddLineToPoint(context, width, height); 134 | 135 | CGContextClosePath(context); 136 | CGContextFillPath(context); 137 | 138 | 139 | // draw the border, bottom with arc 140 | CGContextSetStrokeColorWithColor(context, [strokeColor CGColor]); 141 | CGContextBeginPath(context); 142 | CGContextMoveToPoint(context, indent + MARGIN_LEFT, height); 143 | CGContextAddArcToPoint(context, indent + MARGIN_LEFT, height - MARGIN_BOTTOM, 144 | width, height - MARGIN_BOTTOM, 145 | RADIUS); 146 | CGContextAddLineToPoint(context, width, height - MARGIN_BOTTOM); 147 | 148 | CGContextStrokePath(context); 149 | 150 | } 151 | 152 | // draw the bottom line 153 | if (!self.isOpen) { 154 | int level = self.indentationLevel; 155 | CGFloat indent = (level-1) * self.indentationWidth; 156 | CGContextSetStrokeColorWithColor(context, [strokeColor CGColor]); 157 | CGContextBeginPath(context); 158 | if (level>0) { 159 | CGContextMoveToPoint(context, indent + MARGIN_LEFT, height); 160 | CGContextAddLineToPoint(context, width, height); 161 | } else { 162 | CGContextMoveToPoint(context, 0, height); 163 | CGContextAddLineToPoint(context, width, height); 164 | } 165 | CGContextStrokePath(context); 166 | } 167 | 168 | CGContextRestoreGState(context); 169 | 170 | CGContextSetBlendMode(context, kCGBlendModeClear); 171 | } 172 | 173 | - (id)initWithFrame:(CGRect)frame 174 | { 175 | DBG(@"frame=%@", NSStringFromCGRect(frame)); 176 | self = [super initWithFrame:frame]; 177 | if (self) { 178 | // Initialization code 179 | self.backgroundColor = [UIColor clearColor]; 180 | 181 | self.nameLabel = [[[UILabel alloc] initWithFrame:CGRectZero] autorelease]; 182 | [self.nameLabel setFont:[UIFont fontWithName:@"Helvetica-Bold" size:18]]; 183 | [self.nameLabel setBackgroundColor:[UIColor clearColor]]; 184 | [self.nameLabel setTextColor:[UIColor blackColor]]; 185 | [self.nameLabel setTextAlignment:UITextAlignmentLeft]; 186 | 187 | [self addSubview:self.nameLabel]; 188 | 189 | self.imageView = [[[UIImageView alloc] initWithFrame:CGRectZero] autorelease]; 190 | [self addSubview:self.imageView]; 191 | } 192 | return self; 193 | } 194 | 195 | -(void)dealloc 196 | { 197 | self.nameLabel = nil; 198 | self.imageView = nil; 199 | [super dealloc]; 200 | } 201 | 202 | @end 203 | 204 | ////////////////////////////////////////////////////////////////////// 205 | ////////////////////////////////////////////////////////////////////// 206 | 207 | @interface TreeListTableViewCell () 208 | 209 | @property (nonatomic,retain) IndentView *indentView; 210 | 211 | @end 212 | 213 | @implementation TreeListTableViewCell 214 | 215 | @synthesize indentView; 216 | @synthesize isOpen; 217 | @synthesize hasChildren; 218 | @synthesize name; 219 | 220 | #pragma mark - 221 | #pragma mark accessors 222 | 223 | - (void) layoutSubviews 224 | { 225 | DBGS; 226 | self.indentView.indentationLevel = self.indentationLevel; 227 | self.indentView.indentationWidth = self.indentationWidth; 228 | self.indentView.hasChildren = self.hasChildren; 229 | self.indentView.isOpen = self.isOpen; 230 | 231 | CGRect frame = self.indentView.frame; 232 | DBG(@"self.frame=%@", NSStringFromCGRect(frame)); 233 | frame.size.width = self.frame.size.width; 234 | frame.size.height = self.frame.size.height; 235 | self.indentView.frame = frame; 236 | DBG(@"self.indentView.frame=%@", NSStringFromCGRect(self.indentView.frame)); 237 | 238 | self.indentView.nameLabel.text = self.name; 239 | 240 | [self.indentView setNeedsDisplay]; 241 | [super layoutSubviews]; 242 | } 243 | 244 | #pragma mark - 245 | #pragma mark init and dealloc 246 | 247 | 248 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 249 | 250 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 251 | if (self) { 252 | self.indentationWidth = MARGIN_LEFT; 253 | self.name = @"foo"; 254 | 255 | self.indentView = [[[IndentView alloc] initWithFrame:self.frame] autorelease]; 256 | [[self contentView] addSubview:self.indentView]; 257 | } 258 | return self; 259 | } 260 | 261 | 262 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 263 | 264 | [super setSelected:selected animated:animated]; 265 | } 266 | 267 | 268 | - (void)dealloc { 269 | self.indentView = nil; 270 | [super dealloc]; 271 | } 272 | 273 | @end 274 | 275 | // vim: set sw=4 ts=4 expandtab: 276 | -------------------------------------------------------------------------------- /SBJsonParser.m: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2009,2010 Stig Brautaset. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the author nor the names of its contributors may be used 15 | to endorse or promote products derived from this software without specific 16 | prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #import "SBJsonParser.h" 31 | 32 | @interface SBJsonParser () 33 | 34 | - (BOOL)scanValue:(NSObject **)o; 35 | 36 | - (BOOL)scanRestOfArray:(NSMutableArray **)o; 37 | - (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o; 38 | - (BOOL)scanRestOfNull:(NSNull **)o; 39 | - (BOOL)scanRestOfFalse:(NSNumber **)o; 40 | - (BOOL)scanRestOfTrue:(NSNumber **)o; 41 | - (BOOL)scanRestOfString:(NSMutableString **)o; 42 | 43 | // Cannot manage without looking at the first digit 44 | - (BOOL)scanNumber:(NSNumber **)o; 45 | 46 | - (BOOL)scanHexQuad:(unichar *)x; 47 | - (BOOL)scanUnicodeChar:(unichar *)x; 48 | 49 | - (BOOL)scanIsAtEnd; 50 | 51 | @end 52 | 53 | #define skipWhitespace(c) while (isspace(*c)) c++ 54 | #define skipDigits(c) while (isdigit(*c)) c++ 55 | 56 | 57 | @implementation SBJsonParser 58 | 59 | static char ctrl[0x22]; 60 | 61 | 62 | + (void)initialize { 63 | ctrl[0] = '\"'; 64 | ctrl[1] = '\\'; 65 | for (int i = 1; i < 0x20; i++) 66 | ctrl[i+1] = i; 67 | ctrl[0x21] = 0; 68 | } 69 | 70 | - (id)objectWithString:(NSString *)repr { 71 | [self clearErrorTrace]; 72 | 73 | if (!repr) { 74 | [self addErrorWithCode:EINPUT description:@"Input was 'nil'"]; 75 | return nil; 76 | } 77 | 78 | depth = 0; 79 | c = [repr UTF8String]; 80 | 81 | id o; 82 | if (![self scanValue:&o]) { 83 | return nil; 84 | } 85 | 86 | // We found some valid JSON. But did it also contain something else? 87 | if (![self scanIsAtEnd]) { 88 | [self addErrorWithCode:ETRAILGARBAGE description:@"Garbage after JSON"]; 89 | return nil; 90 | } 91 | 92 | NSAssert1(o, @"Should have a valid object from %@", repr); 93 | 94 | // Check that the object we've found is a valid JSON container. 95 | if (![o isKindOfClass:[NSDictionary class]] && ![o isKindOfClass:[NSArray class]]) { 96 | [self addErrorWithCode:EFRAGMENT description:@"Valid fragment, but not JSON"]; 97 | return nil; 98 | } 99 | 100 | return o; 101 | } 102 | 103 | - (id)objectWithString:(NSString*)repr error:(NSError**)error { 104 | id tmp = [self objectWithString:repr]; 105 | if (tmp) 106 | return tmp; 107 | 108 | if (error) 109 | *error = [self.errorTrace lastObject]; 110 | return nil; 111 | } 112 | 113 | 114 | /* 115 | In contrast to the public methods, it is an error to omit the error parameter here. 116 | */ 117 | - (BOOL)scanValue:(NSObject **)o 118 | { 119 | skipWhitespace(c); 120 | 121 | switch (*c++) { 122 | case '{': 123 | return [self scanRestOfDictionary:(NSMutableDictionary **)o]; 124 | break; 125 | case '[': 126 | return [self scanRestOfArray:(NSMutableArray **)o]; 127 | break; 128 | case '"': 129 | return [self scanRestOfString:(NSMutableString **)o]; 130 | break; 131 | case 'f': 132 | return [self scanRestOfFalse:(NSNumber **)o]; 133 | break; 134 | case 't': 135 | return [self scanRestOfTrue:(NSNumber **)o]; 136 | break; 137 | case 'n': 138 | return [self scanRestOfNull:(NSNull **)o]; 139 | break; 140 | case '-': 141 | case '0'...'9': 142 | c--; // cannot verify number correctly without the first character 143 | return [self scanNumber:(NSNumber **)o]; 144 | break; 145 | case '+': 146 | [self addErrorWithCode:EPARSENUM description: @"Leading + disallowed in number"]; 147 | return NO; 148 | break; 149 | case 0x0: 150 | [self addErrorWithCode:EEOF description:@"Unexpected end of string"]; 151 | return NO; 152 | break; 153 | default: 154 | [self addErrorWithCode:EPARSE description: @"Unrecognised leading character"]; 155 | return NO; 156 | break; 157 | } 158 | 159 | NSAssert(0, @"Should never get here"); 160 | return NO; 161 | } 162 | 163 | - (BOOL)scanRestOfTrue:(NSNumber **)o 164 | { 165 | if (!strncmp(c, "rue", 3)) { 166 | c += 3; 167 | *o = [NSNumber numberWithBool:YES]; 168 | return YES; 169 | } 170 | [self addErrorWithCode:EPARSE description:@"Expected 'true'"]; 171 | return NO; 172 | } 173 | 174 | - (BOOL)scanRestOfFalse:(NSNumber **)o 175 | { 176 | if (!strncmp(c, "alse", 4)) { 177 | c += 4; 178 | *o = [NSNumber numberWithBool:NO]; 179 | return YES; 180 | } 181 | [self addErrorWithCode:EPARSE description: @"Expected 'false'"]; 182 | return NO; 183 | } 184 | 185 | - (BOOL)scanRestOfNull:(NSNull **)o { 186 | if (!strncmp(c, "ull", 3)) { 187 | c += 3; 188 | *o = [NSNull null]; 189 | return YES; 190 | } 191 | [self addErrorWithCode:EPARSE description: @"Expected 'null'"]; 192 | return NO; 193 | } 194 | 195 | - (BOOL)scanRestOfArray:(NSMutableArray **)o { 196 | if (maxDepth && ++depth > maxDepth) { 197 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 198 | return NO; 199 | } 200 | 201 | *o = [NSMutableArray arrayWithCapacity:8]; 202 | 203 | for (; *c ;) { 204 | id v; 205 | 206 | skipWhitespace(c); 207 | if (*c == ']' && c++) { 208 | depth--; 209 | return YES; 210 | } 211 | 212 | if (![self scanValue:&v]) { 213 | [self addErrorWithCode:EPARSE description:@"Expected value while parsing array"]; 214 | return NO; 215 | } 216 | 217 | [*o addObject:v]; 218 | 219 | skipWhitespace(c); 220 | if (*c == ',' && c++) { 221 | skipWhitespace(c); 222 | if (*c == ']') { 223 | [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in array"]; 224 | return NO; 225 | } 226 | } 227 | } 228 | 229 | [self addErrorWithCode:EEOF description: @"End of input while parsing array"]; 230 | return NO; 231 | } 232 | 233 | - (BOOL)scanRestOfDictionary:(NSMutableDictionary **)o 234 | { 235 | if (maxDepth && ++depth > maxDepth) { 236 | [self addErrorWithCode:EDEPTH description: @"Nested too deep"]; 237 | return NO; 238 | } 239 | 240 | *o = [NSMutableDictionary dictionaryWithCapacity:7]; 241 | 242 | for (; *c ;) { 243 | id k, v; 244 | 245 | skipWhitespace(c); 246 | if (*c == '}' && c++) { 247 | depth--; 248 | return YES; 249 | } 250 | 251 | if (!(*c == '\"' && c++ && [self scanRestOfString:&k])) { 252 | [self addErrorWithCode:EPARSE description: @"Object key string expected"]; 253 | return NO; 254 | } 255 | 256 | skipWhitespace(c); 257 | if (*c != ':') { 258 | [self addErrorWithCode:EPARSE description: @"Expected ':' separating key and value"]; 259 | return NO; 260 | } 261 | 262 | c++; 263 | if (![self scanValue:&v]) { 264 | NSString *string = [NSString stringWithFormat:@"Object value expected for key: %@", k]; 265 | [self addErrorWithCode:EPARSE description: string]; 266 | return NO; 267 | } 268 | 269 | [*o setObject:v forKey:k]; 270 | 271 | skipWhitespace(c); 272 | if (*c == ',' && c++) { 273 | skipWhitespace(c); 274 | if (*c == '}') { 275 | [self addErrorWithCode:ETRAILCOMMA description: @"Trailing comma disallowed in object"]; 276 | return NO; 277 | } 278 | } 279 | } 280 | 281 | [self addErrorWithCode:EEOF description: @"End of input while parsing object"]; 282 | return NO; 283 | } 284 | 285 | - (BOOL)scanRestOfString:(NSMutableString **)o 286 | { 287 | // if the string has no control characters in it, return it in one go, without any temporary allocations. 288 | size_t len = strcspn(c, ctrl); 289 | if (len && *(c + len) == '\"') 290 | { 291 | *o = [[[NSMutableString alloc] initWithBytes:(char*)c length:len encoding:NSUTF8StringEncoding] autorelease]; 292 | c += len + 1; 293 | return YES; 294 | } 295 | 296 | *o = [NSMutableString stringWithCapacity:16]; 297 | do { 298 | // First see if there's a portion we can grab in one go. 299 | // Doing this caused a massive speedup on the long string. 300 | len = strcspn(c, ctrl); 301 | if (len) { 302 | // check for 303 | id t = [[NSString alloc] initWithBytesNoCopy:(char*)c 304 | length:len 305 | encoding:NSUTF8StringEncoding 306 | freeWhenDone:NO]; 307 | if (t) { 308 | [*o appendString:t]; 309 | [t release]; 310 | c += len; 311 | } 312 | } 313 | 314 | if (*c == '"') { 315 | c++; 316 | return YES; 317 | 318 | } else if (*c == '\\') { 319 | unichar uc = *++c; 320 | switch (uc) { 321 | case '\\': 322 | case '/': 323 | case '"': 324 | break; 325 | 326 | case 'b': uc = '\b'; break; 327 | case 'n': uc = '\n'; break; 328 | case 'r': uc = '\r'; break; 329 | case 't': uc = '\t'; break; 330 | case 'f': uc = '\f'; break; 331 | 332 | case 'u': 333 | c++; 334 | if (![self scanUnicodeChar:&uc]) { 335 | [self addErrorWithCode:EUNICODE description: @"Broken unicode character"]; 336 | return NO; 337 | } 338 | c--; // hack. 339 | break; 340 | default: 341 | [self addErrorWithCode:EESCAPE description: [NSString stringWithFormat:@"Illegal escape sequence '0x%x'", uc]]; 342 | return NO; 343 | break; 344 | } 345 | CFStringAppendCharacters((CFMutableStringRef)*o, &uc, 1); 346 | c++; 347 | 348 | } else if (*c < 0x20) { 349 | [self addErrorWithCode:ECTRL description: [NSString stringWithFormat:@"Unescaped control character '0x%x'", *c]]; 350 | return NO; 351 | 352 | } else { 353 | NSLog(@"should not be able to get here"); 354 | } 355 | } while (*c); 356 | 357 | [self addErrorWithCode:EEOF description:@"Unexpected EOF while parsing string"]; 358 | return NO; 359 | } 360 | 361 | - (BOOL)scanUnicodeChar:(unichar *)x 362 | { 363 | unichar hi, lo; 364 | 365 | if (![self scanHexQuad:&hi]) { 366 | [self addErrorWithCode:EUNICODE description: @"Missing hex quad"]; 367 | return NO; 368 | } 369 | 370 | if (hi >= 0xd800) { // high surrogate char? 371 | if (hi < 0xdc00) { // yes - expect a low char 372 | 373 | if (!(*c == '\\' && ++c && *c == 'u' && ++c && [self scanHexQuad:&lo])) { 374 | [self addErrorWithCode:EUNICODE description: @"Missing low character in surrogate pair"]; 375 | return NO; 376 | } 377 | 378 | if (lo < 0xdc00 || lo >= 0xdfff) { 379 | [self addErrorWithCode:EUNICODE description:@"Invalid low surrogate char"]; 380 | return NO; 381 | } 382 | 383 | hi = (hi - 0xd800) * 0x400 + (lo - 0xdc00) + 0x10000; 384 | 385 | } else if (hi < 0xe000) { 386 | [self addErrorWithCode:EUNICODE description:@"Invalid high character in surrogate pair"]; 387 | return NO; 388 | } 389 | } 390 | 391 | *x = hi; 392 | return YES; 393 | } 394 | 395 | - (BOOL)scanHexQuad:(unichar *)x 396 | { 397 | *x = 0; 398 | for (int i = 0; i < 4; i++) { 399 | unichar uc = *c; 400 | c++; 401 | int d = (uc >= '0' && uc <= '9') 402 | ? uc - '0' : (uc >= 'a' && uc <= 'f') 403 | ? (uc - 'a' + 10) : (uc >= 'A' && uc <= 'F') 404 | ? (uc - 'A' + 10) : -1; 405 | if (d == -1) { 406 | [self addErrorWithCode:EUNICODE description:@"Missing hex digit in quad"]; 407 | return NO; 408 | } 409 | *x *= 16; 410 | *x += d; 411 | } 412 | return YES; 413 | } 414 | 415 | - (BOOL)scanNumber:(NSNumber **)o 416 | { 417 | BOOL simple = YES; 418 | 419 | const char *ns = c; 420 | 421 | // The logic to test for validity of the number formatting is relicensed 422 | // from JSON::XS with permission from its author Marc Lehmann. 423 | // (Available at the CPAN: http://search.cpan.org/dist/JSON-XS/ .) 424 | 425 | if ('-' == *c) 426 | c++; 427 | 428 | if ('0' == *c && c++) { 429 | if (isdigit(*c)) { 430 | [self addErrorWithCode:EPARSENUM description: @"Leading 0 disallowed in number"]; 431 | return NO; 432 | } 433 | 434 | } else if (!isdigit(*c) && c != ns) { 435 | [self addErrorWithCode:EPARSENUM description: @"No digits after initial minus"]; 436 | return NO; 437 | 438 | } else { 439 | skipDigits(c); 440 | } 441 | 442 | // Fractional part 443 | if ('.' == *c && c++) { 444 | simple = NO; 445 | if (!isdigit(*c)) { 446 | [self addErrorWithCode:EPARSENUM description: @"No digits after decimal point"]; 447 | return NO; 448 | } 449 | skipDigits(c); 450 | } 451 | 452 | // Exponential part 453 | if ('e' == *c || 'E' == *c) { 454 | simple = NO; 455 | c++; 456 | 457 | if ('-' == *c || '+' == *c) 458 | c++; 459 | 460 | if (!isdigit(*c)) { 461 | [self addErrorWithCode:EPARSENUM description: @"No digits after exponent"]; 462 | return NO; 463 | } 464 | skipDigits(c); 465 | } 466 | 467 | // If we are only reading integers, don't go through the expense of creating an NSDecimal. 468 | // This ends up being a very large perf win. 469 | if (simple) { 470 | BOOL negate = NO; 471 | long long val = 0; 472 | const char *d = ns; 473 | 474 | if (*d == '-') { 475 | negate = YES; 476 | d++; 477 | } 478 | 479 | while (isdigit(*d)) { 480 | val *= 10; 481 | if (val < 0) 482 | goto longlong_overflow; 483 | val += *d - '0'; 484 | if (val < 0) 485 | goto longlong_overflow; 486 | d++; 487 | } 488 | 489 | *o = [NSNumber numberWithLongLong:negate ? -val : val]; 490 | return YES; 491 | 492 | } else { 493 | // jumped to by simple branch, if an overflow occured 494 | longlong_overflow:; 495 | 496 | id str = [[NSString alloc] initWithBytesNoCopy:(char*)ns 497 | length:c - ns 498 | encoding:NSUTF8StringEncoding 499 | freeWhenDone:NO]; 500 | [str autorelease]; 501 | if (str && (*o = [NSDecimalNumber decimalNumberWithString:str])) 502 | return YES; 503 | 504 | [self addErrorWithCode:EPARSENUM description: @"Failed creating decimal instance"]; 505 | return NO; 506 | } 507 | } 508 | 509 | - (BOOL)scanIsAtEnd 510 | { 511 | skipWhitespace(c); 512 | return !*c; 513 | } 514 | 515 | 516 | @end 517 | -------------------------------------------------------------------------------- /TreeList.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1D3623260D0F684500981E51 /* TreeListAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* TreeListAppDelegate.m */; }; 11 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 12 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 13 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 14 | 2892E4100DC94CBA00A64D0F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */; }; 15 | 28AD73600D9D9599002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD735F0D9D9599002E5188 /* MainWindow.xib */; }; 16 | 28C286E10D94DF7D0034E888 /* RootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28C286E00D94DF7D0034E888 /* RootViewController.m */; }; 17 | 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28F335F01007B36200424DE2 /* RootViewController.xib */; }; 18 | BF38C59D1377EDB20072AD3C /* TreeListModel.m in Sources */ = {isa = PBXBuildFile; fileRef = BF38C59C1377EDB20072AD3C /* TreeListModel.m */; }; 19 | BF38C6A413782FF30072AD3C /* MainWindow-iPad.xib in Resources */ = {isa = PBXBuildFile; fileRef = BF38C6A313782FF30072AD3C /* MainWindow-iPad.xib */; }; 20 | BF38C6C2137844190072AD3C /* TreeListTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = BF38C6C1137844190072AD3C /* TreeListTableViewCell.m */; }; 21 | BF5C98341373F6FA00000929 /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = BF5C982A1373F6FA00000929 /* SBJsonWriter.m */; }; 22 | BF5C98351373F6FA00000929 /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = BF5C982C1373F6FA00000929 /* SBJsonParser.m */; }; 23 | BF5C98361373F6FA00000929 /* SBJsonBase.m in Sources */ = {isa = PBXBuildFile; fileRef = BF5C982E1373F6FA00000929 /* SBJsonBase.m */; }; 24 | BF5C98371373F6FA00000929 /* NSString+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = BF5C98301373F6FA00000929 /* NSString+SBJSON.m */; }; 25 | BF5C98381373F6FA00000929 /* NSObject+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = BF5C98321373F6FA00000929 /* NSObject+SBJSON.m */; }; 26 | BF5C98B71373FD7900000929 /* contents.json in Resources */ = {isa = PBXBuildFile; fileRef = BF5C98B61373FD7900000929 /* contents.json */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 31 | 1D3623240D0F684500981E51 /* TreeListAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TreeListAppDelegate.h; sourceTree = ""; }; 32 | 1D3623250D0F684500981E51 /* TreeListAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TreeListAppDelegate.m; sourceTree = ""; }; 33 | 1D6058910D05DD3D006BFB54 /* TreeList.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TreeList.app; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 35 | 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 36 | 28A0AAE50D9B0CCF005BE974 /* TreeList_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TreeList_Prefix.pch; sourceTree = ""; }; 37 | 28AD735F0D9D9599002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; explicitFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 38 | 28C286DF0D94DF7D0034E888 /* RootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RootViewController.h; sourceTree = ""; }; 39 | 28C286E00D94DF7D0034E888 /* RootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RootViewController.m; sourceTree = ""; }; 40 | 28F335F01007B36200424DE2 /* RootViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RootViewController.xib; sourceTree = ""; }; 41 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 42 | 8D1107310486CEB800E47090 /* TreeList-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "TreeList-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; 43 | BF38C59B1377EDB20072AD3C /* TreeListModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TreeListModel.h; sourceTree = ""; }; 44 | BF38C59C1377EDB20072AD3C /* TreeListModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TreeListModel.m; sourceTree = ""; }; 45 | BF38C6A313782FF30072AD3C /* MainWindow-iPad.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = "MainWindow-iPad.xib"; path = "Resources-iPad/MainWindow-iPad.xib"; sourceTree = ""; }; 46 | BF38C6C0137844190072AD3C /* TreeListTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TreeListTableViewCell.h; sourceTree = ""; }; 47 | BF38C6C1137844190072AD3C /* TreeListTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TreeListTableViewCell.m; sourceTree = ""; }; 48 | BF5C98291373F6FA00000929 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; 49 | BF5C982A1373F6FA00000929 /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = ""; }; 50 | BF5C982B1373F6FA00000929 /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = ""; }; 51 | BF5C982C1373F6FA00000929 /* SBJsonParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonParser.m; sourceTree = ""; }; 52 | BF5C982D1373F6FA00000929 /* SBJsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonParser.h; sourceTree = ""; }; 53 | BF5C982E1373F6FA00000929 /* SBJsonBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonBase.m; sourceTree = ""; }; 54 | BF5C982F1373F6FA00000929 /* SBJsonBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonBase.h; sourceTree = ""; }; 55 | BF5C98301373F6FA00000929 /* NSString+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SBJSON.m"; sourceTree = ""; }; 56 | BF5C98311373F6FA00000929 /* NSString+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SBJSON.h"; sourceTree = ""; }; 57 | BF5C98321373F6FA00000929 /* NSObject+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SBJSON.m"; sourceTree = ""; }; 58 | BF5C98331373F6FA00000929 /* NSObject+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SBJSON.h"; sourceTree = ""; }; 59 | BF5C98B61373FD7900000929 /* contents.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = contents.json; sourceTree = ""; }; 60 | /* End PBXFileReference section */ 61 | 62 | /* Begin PBXFrameworksBuildPhase section */ 63 | 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, 68 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 69 | 2892E4100DC94CBA00A64D0F /* CoreGraphics.framework in Frameworks */, 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | /* End PBXFrameworksBuildPhase section */ 74 | 75 | /* Begin PBXGroup section */ 76 | 080E96DDFE201D6D7F000001 /* Classes */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 28C286DF0D94DF7D0034E888 /* RootViewController.h */, 80 | 28C286E00D94DF7D0034E888 /* RootViewController.m */, 81 | 1D3623240D0F684500981E51 /* TreeListAppDelegate.h */, 82 | 1D3623250D0F684500981E51 /* TreeListAppDelegate.m */, 83 | BF38C59B1377EDB20072AD3C /* TreeListModel.h */, 84 | BF38C59C1377EDB20072AD3C /* TreeListModel.m */, 85 | BF38C6C0137844190072AD3C /* TreeListTableViewCell.h */, 86 | BF38C6C1137844190072AD3C /* TreeListTableViewCell.m */, 87 | ); 88 | path = Classes; 89 | sourceTree = ""; 90 | }; 91 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 1D6058910D05DD3D006BFB54 /* TreeList.app */, 95 | ); 96 | name = Products; 97 | sourceTree = ""; 98 | }; 99 | 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 080E96DDFE201D6D7F000001 /* Classes */, 103 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 104 | 29B97317FDCFA39411CA2CEA /* Resources */, 105 | BF38C6A213782FF20072AD3C /* Resources-iPad */, 106 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 107 | 19C28FACFE9D520D11CA2CBB /* Products */, 108 | ); 109 | name = CustomTemplate; 110 | sourceTree = ""; 111 | }; 112 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | BF5C98281373F6FA00000929 /* SBJSON */, 116 | 28A0AAE50D9B0CCF005BE974 /* TreeList_Prefix.pch */, 117 | 29B97316FDCFA39411CA2CEA /* main.m */, 118 | ); 119 | name = "Other Sources"; 120 | sourceTree = ""; 121 | }; 122 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | BF5C98B61373FD7900000929 /* contents.json */, 126 | 28F335F01007B36200424DE2 /* RootViewController.xib */, 127 | 28AD735F0D9D9599002E5188 /* MainWindow.xib */, 128 | 8D1107310486CEB800E47090 /* TreeList-Info.plist */, 129 | ); 130 | name = Resources; 131 | sourceTree = ""; 132 | }; 133 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 137 | 1D30AB110D05D00D00671497 /* Foundation.framework */, 138 | 2892E40F0DC94CBA00A64D0F /* CoreGraphics.framework */, 139 | ); 140 | name = Frameworks; 141 | sourceTree = ""; 142 | }; 143 | BF38C6A213782FF20072AD3C /* Resources-iPad */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | BF38C6A313782FF30072AD3C /* MainWindow-iPad.xib */, 147 | ); 148 | name = "Resources-iPad"; 149 | sourceTree = ""; 150 | }; 151 | BF5C98281373F6FA00000929 /* SBJSON */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | BF5C98291373F6FA00000929 /* JSON.h */, 155 | BF5C982A1373F6FA00000929 /* SBJsonWriter.m */, 156 | BF5C982B1373F6FA00000929 /* SBJsonWriter.h */, 157 | BF5C982C1373F6FA00000929 /* SBJsonParser.m */, 158 | BF5C982D1373F6FA00000929 /* SBJsonParser.h */, 159 | BF5C982E1373F6FA00000929 /* SBJsonBase.m */, 160 | BF5C982F1373F6FA00000929 /* SBJsonBase.h */, 161 | BF5C98301373F6FA00000929 /* NSString+SBJSON.m */, 162 | BF5C98311373F6FA00000929 /* NSString+SBJSON.h */, 163 | BF5C98321373F6FA00000929 /* NSObject+SBJSON.m */, 164 | BF5C98331373F6FA00000929 /* NSObject+SBJSON.h */, 165 | ); 166 | name = SBJSON; 167 | sourceTree = ""; 168 | }; 169 | /* End PBXGroup section */ 170 | 171 | /* Begin PBXNativeTarget section */ 172 | 1D6058900D05DD3D006BFB54 /* TreeList */ = { 173 | isa = PBXNativeTarget; 174 | buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "TreeList" */; 175 | buildPhases = ( 176 | 1D60588D0D05DD3D006BFB54 /* Resources */, 177 | 1D60588E0D05DD3D006BFB54 /* Sources */, 178 | 1D60588F0D05DD3D006BFB54 /* Frameworks */, 179 | ); 180 | buildRules = ( 181 | ); 182 | dependencies = ( 183 | ); 184 | name = TreeList; 185 | productName = TreeList; 186 | productReference = 1D6058910D05DD3D006BFB54 /* TreeList.app */; 187 | productType = "com.apple.product-type.application"; 188 | }; 189 | /* End PBXNativeTarget section */ 190 | 191 | /* Begin PBXProject section */ 192 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 193 | isa = PBXProject; 194 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "TreeList" */; 195 | compatibilityVersion = "Xcode 3.2"; 196 | developmentRegion = English; 197 | hasScannedForEncodings = 1; 198 | knownRegions = ( 199 | English, 200 | Japanese, 201 | French, 202 | German, 203 | en, 204 | ); 205 | mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; 206 | projectDirPath = ""; 207 | projectRoot = ""; 208 | targets = ( 209 | 1D6058900D05DD3D006BFB54 /* TreeList */, 210 | ); 211 | }; 212 | /* End PBXProject section */ 213 | 214 | /* Begin PBXResourcesBuildPhase section */ 215 | 1D60588D0D05DD3D006BFB54 /* Resources */ = { 216 | isa = PBXResourcesBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | 28AD73600D9D9599002E5188 /* MainWindow.xib in Resources */, 220 | 28F335F11007B36200424DE2 /* RootViewController.xib in Resources */, 221 | BF5C98B71373FD7900000929 /* contents.json in Resources */, 222 | BF38C6A413782FF30072AD3C /* MainWindow-iPad.xib in Resources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | /* End PBXResourcesBuildPhase section */ 227 | 228 | /* Begin PBXSourcesBuildPhase section */ 229 | 1D60588E0D05DD3D006BFB54 /* Sources */ = { 230 | isa = PBXSourcesBuildPhase; 231 | buildActionMask = 2147483647; 232 | files = ( 233 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 234 | 1D3623260D0F684500981E51 /* TreeListAppDelegate.m in Sources */, 235 | 28C286E10D94DF7D0034E888 /* RootViewController.m in Sources */, 236 | BF5C98341373F6FA00000929 /* SBJsonWriter.m in Sources */, 237 | BF5C98351373F6FA00000929 /* SBJsonParser.m in Sources */, 238 | BF5C98361373F6FA00000929 /* SBJsonBase.m in Sources */, 239 | BF5C98371373F6FA00000929 /* NSString+SBJSON.m in Sources */, 240 | BF5C98381373F6FA00000929 /* NSObject+SBJSON.m in Sources */, 241 | BF38C59D1377EDB20072AD3C /* TreeListModel.m in Sources */, 242 | BF38C6C2137844190072AD3C /* TreeListTableViewCell.m in Sources */, 243 | ); 244 | runOnlyForDeploymentPostprocessing = 0; 245 | }; 246 | /* End PBXSourcesBuildPhase section */ 247 | 248 | /* Begin XCBuildConfiguration section */ 249 | 1D6058940D05DD3E006BFB54 /* Debug */ = { 250 | isa = XCBuildConfiguration; 251 | buildSettings = { 252 | ALWAYS_SEARCH_USER_PATHS = NO; 253 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 254 | COPY_PHASE_STRIP = NO; 255 | GCC_DYNAMIC_NO_PIC = NO; 256 | GCC_OPTIMIZATION_LEVEL = 0; 257 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 258 | GCC_PREFIX_HEADER = TreeList_Prefix.pch; 259 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG; 260 | INFOPLIST_FILE = "TreeList-Info.plist"; 261 | PRODUCT_NAME = TreeList; 262 | SDKROOT = iphoneos; 263 | TARGETED_DEVICE_FAMILY = "1,2"; 264 | }; 265 | name = Debug; 266 | }; 267 | 1D6058950D05DD3E006BFB54 /* Release */ = { 268 | isa = XCBuildConfiguration; 269 | buildSettings = { 270 | ALWAYS_SEARCH_USER_PATHS = NO; 271 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 272 | COPY_PHASE_STRIP = YES; 273 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 274 | GCC_PREFIX_HEADER = TreeList_Prefix.pch; 275 | INFOPLIST_FILE = "TreeList-Info.plist"; 276 | PRODUCT_NAME = TreeList; 277 | SDKROOT = iphoneos; 278 | TARGETED_DEVICE_FAMILY = "1,2"; 279 | VALIDATE_PRODUCT = YES; 280 | }; 281 | name = Release; 282 | }; 283 | C01FCF4F08A954540054247B /* Debug */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 287 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 288 | GCC_C_LANGUAGE_STANDARD = c99; 289 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 290 | GCC_WARN_UNUSED_VARIABLE = YES; 291 | PREBINDING = NO; 292 | SDKROOT = iphoneos; 293 | }; 294 | name = Debug; 295 | }; 296 | C01FCF5008A954540054247B /* Release */ = { 297 | isa = XCBuildConfiguration; 298 | buildSettings = { 299 | ARCHS = "$(ARCHS_STANDARD_32_BIT)"; 300 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 301 | GCC_C_LANGUAGE_STANDARD = c99; 302 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 303 | GCC_WARN_UNUSED_VARIABLE = YES; 304 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 305 | PREBINDING = NO; 306 | SDKROOT = iphoneos; 307 | }; 308 | name = Release; 309 | }; 310 | /* End XCBuildConfiguration section */ 311 | 312 | /* Begin XCConfigurationList section */ 313 | 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "TreeList" */ = { 314 | isa = XCConfigurationList; 315 | buildConfigurations = ( 316 | 1D6058940D05DD3E006BFB54 /* Debug */, 317 | 1D6058950D05DD3E006BFB54 /* Release */, 318 | ); 319 | defaultConfigurationIsVisible = 0; 320 | defaultConfigurationName = Release; 321 | }; 322 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "TreeList" */ = { 323 | isa = XCConfigurationList; 324 | buildConfigurations = ( 325 | C01FCF4F08A954540054247B /* Debug */, 326 | C01FCF5008A954540054247B /* Release */, 327 | ); 328 | defaultConfigurationIsVisible = 0; 329 | defaultConfigurationName = Release; 330 | }; 331 | /* End XCConfigurationList section */ 332 | }; 333 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 334 | } 335 | -------------------------------------------------------------------------------- /RootViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1056 5 | 10J869 6 | 851 7 | 1038.35 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 141 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | 42 | 274 43 | {320, 247} 44 | 45 | 46 | 3 47 | MQA 48 | 49 | NO 50 | YES 51 | NO 52 | 53 | 3 54 | 55 | IBCocoaTouchFramework 56 | NO 57 | 0 58 | YES 59 | 44 60 | 22 61 | 22 62 | 63 | 64 | 65 | 66 | YES 67 | 68 | 69 | view 70 | 71 | 72 | 73 | 3 74 | 75 | 76 | 77 | dataSource 78 | 79 | 80 | 81 | 4 82 | 83 | 84 | 85 | delegate 86 | 87 | 88 | 89 | 5 90 | 91 | 92 | 93 | 94 | YES 95 | 96 | 0 97 | 98 | 99 | 100 | 101 | 102 | -1 103 | 104 | 105 | File's Owner 106 | 107 | 108 | -2 109 | 110 | 111 | 112 | 113 | 2 114 | 115 | 116 | 117 | 118 | 119 | 120 | YES 121 | 122 | YES 123 | -1.CustomClassName 124 | -2.CustomClassName 125 | 2.IBEditorWindowLastContentRect 126 | 2.IBPluginDependency 127 | 128 | 129 | YES 130 | RootViewController 131 | UIResponder 132 | {{144, 609}, {320, 247}} 133 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 134 | 135 | 136 | 137 | YES 138 | 139 | 140 | YES 141 | 142 | 143 | 144 | 145 | YES 146 | 147 | 148 | YES 149 | 150 | 151 | 152 | 5 153 | 154 | 155 | 156 | YES 157 | 158 | NSObject 159 | 160 | IBProjectSource 161 | NSObject+SBJSON.h 162 | 163 | 164 | 165 | NSObject 166 | 167 | IBProjectSource 168 | SBJsonWriter.h 169 | 170 | 171 | 172 | RootViewController 173 | UITableViewController 174 | 175 | IBProjectSource 176 | Classes/RootViewController.h 177 | 178 | 179 | 180 | 181 | YES 182 | 183 | NSObject 184 | 185 | IBFrameworkSource 186 | Foundation.framework/Headers/NSError.h 187 | 188 | 189 | 190 | NSObject 191 | 192 | IBFrameworkSource 193 | Foundation.framework/Headers/NSFileManager.h 194 | 195 | 196 | 197 | NSObject 198 | 199 | IBFrameworkSource 200 | Foundation.framework/Headers/NSKeyValueCoding.h 201 | 202 | 203 | 204 | NSObject 205 | 206 | IBFrameworkSource 207 | Foundation.framework/Headers/NSKeyValueObserving.h 208 | 209 | 210 | 211 | NSObject 212 | 213 | IBFrameworkSource 214 | Foundation.framework/Headers/NSKeyedArchiver.h 215 | 216 | 217 | 218 | NSObject 219 | 220 | IBFrameworkSource 221 | Foundation.framework/Headers/NSObject.h 222 | 223 | 224 | 225 | NSObject 226 | 227 | IBFrameworkSource 228 | Foundation.framework/Headers/NSRunLoop.h 229 | 230 | 231 | 232 | NSObject 233 | 234 | IBFrameworkSource 235 | Foundation.framework/Headers/NSThread.h 236 | 237 | 238 | 239 | NSObject 240 | 241 | IBFrameworkSource 242 | Foundation.framework/Headers/NSURL.h 243 | 244 | 245 | 246 | NSObject 247 | 248 | IBFrameworkSource 249 | Foundation.framework/Headers/NSURLConnection.h 250 | 251 | 252 | 253 | NSObject 254 | 255 | IBFrameworkSource 256 | UIKit.framework/Headers/UIAccessibility.h 257 | 258 | 259 | 260 | NSObject 261 | 262 | IBFrameworkSource 263 | UIKit.framework/Headers/UINibLoading.h 264 | 265 | 266 | 267 | NSObject 268 | 269 | IBFrameworkSource 270 | UIKit.framework/Headers/UIResponder.h 271 | 272 | 273 | 274 | UIResponder 275 | NSObject 276 | 277 | 278 | 279 | UIScrollView 280 | UIView 281 | 282 | IBFrameworkSource 283 | UIKit.framework/Headers/UIScrollView.h 284 | 285 | 286 | 287 | UISearchBar 288 | UIView 289 | 290 | IBFrameworkSource 291 | UIKit.framework/Headers/UISearchBar.h 292 | 293 | 294 | 295 | UISearchDisplayController 296 | NSObject 297 | 298 | IBFrameworkSource 299 | UIKit.framework/Headers/UISearchDisplayController.h 300 | 301 | 302 | 303 | UITableView 304 | UIScrollView 305 | 306 | IBFrameworkSource 307 | UIKit.framework/Headers/UITableView.h 308 | 309 | 310 | 311 | UITableViewController 312 | UIViewController 313 | 314 | IBFrameworkSource 315 | UIKit.framework/Headers/UITableViewController.h 316 | 317 | 318 | 319 | UIView 320 | 321 | IBFrameworkSource 322 | UIKit.framework/Headers/UIPrintFormatter.h 323 | 324 | 325 | 326 | UIView 327 | 328 | IBFrameworkSource 329 | UIKit.framework/Headers/UITextField.h 330 | 331 | 332 | 333 | UIView 334 | UIResponder 335 | 336 | IBFrameworkSource 337 | UIKit.framework/Headers/UIView.h 338 | 339 | 340 | 341 | UIViewController 342 | 343 | IBFrameworkSource 344 | UIKit.framework/Headers/UINavigationController.h 345 | 346 | 347 | 348 | UIViewController 349 | 350 | IBFrameworkSource 351 | UIKit.framework/Headers/UIPopoverController.h 352 | 353 | 354 | 355 | UIViewController 356 | 357 | IBFrameworkSource 358 | UIKit.framework/Headers/UISplitViewController.h 359 | 360 | 361 | 362 | UIViewController 363 | 364 | IBFrameworkSource 365 | UIKit.framework/Headers/UITabBarController.h 366 | 367 | 368 | 369 | UIViewController 370 | UIResponder 371 | 372 | IBFrameworkSource 373 | UIKit.framework/Headers/UIViewController.h 374 | 375 | 376 | 377 | 378 | 0 379 | IBCocoaTouchFramework 380 | 381 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 382 | 383 | 384 | 385 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 386 | 387 | 388 | YES 389 | TreeList.xcodeproj 390 | 3 391 | 141 392 | 393 | 394 | -------------------------------------------------------------------------------- /MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1024 5 | 10D571 6 | 786 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 112 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | IBCocoaTouchFramework 42 | 43 | 44 | 45 | 1316 46 | 47 | {320, 480} 48 | 49 | 1 50 | MSAxIDEAA 51 | 52 | NO 53 | NO 54 | 55 | IBCocoaTouchFramework 56 | YES 57 | 58 | 59 | 60 | 61 | 1 62 | 63 | IBCocoaTouchFramework 64 | NO 65 | 66 | 67 | 256 68 | {0, 0} 69 | NO 70 | YES 71 | YES 72 | IBCocoaTouchFramework 73 | 74 | 75 | YES 76 | 77 | 78 | 79 | IBCocoaTouchFramework 80 | 81 | 82 | RootViewController 83 | 84 | 85 | 1 86 | 87 | IBCocoaTouchFramework 88 | NO 89 | 90 | 91 | 92 | 93 | 94 | 95 | YES 96 | 97 | 98 | delegate 99 | 100 | 101 | 102 | 4 103 | 104 | 105 | 106 | window 107 | 108 | 109 | 110 | 5 111 | 112 | 113 | 114 | navigationController 115 | 116 | 117 | 118 | 15 119 | 120 | 121 | 122 | 123 | YES 124 | 125 | 0 126 | 127 | 128 | 129 | 130 | 131 | 2 132 | 133 | 134 | YES 135 | 136 | 137 | 138 | 139 | -1 140 | 141 | 142 | File's Owner 143 | 144 | 145 | 3 146 | 147 | 148 | 149 | 150 | -2 151 | 152 | 153 | 154 | 155 | 9 156 | 157 | 158 | YES 159 | 160 | 161 | 162 | 163 | 164 | 165 | 11 166 | 167 | 168 | 169 | 170 | 13 171 | 172 | 173 | YES 174 | 175 | 176 | 177 | 178 | 179 | 14 180 | 181 | 182 | 183 | 184 | 185 | 186 | YES 187 | 188 | YES 189 | -1.CustomClassName 190 | -2.CustomClassName 191 | 11.IBPluginDependency 192 | 13.CustomClassName 193 | 13.IBPluginDependency 194 | 2.IBAttributePlaceholdersKey 195 | 2.IBEditorWindowLastContentRect 196 | 2.IBPluginDependency 197 | 3.CustomClassName 198 | 3.IBPluginDependency 199 | 9.IBEditorWindowLastContentRect 200 | 9.IBPluginDependency 201 | 202 | 203 | YES 204 | UIApplication 205 | UIResponder 206 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 207 | RootViewController 208 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 209 | 210 | YES 211 | 212 | 213 | YES 214 | 215 | 216 | {{673, 376}, {320, 480}} 217 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 218 | TreeListAppDelegate 219 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 220 | {{186, 376}, {320, 480}} 221 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 222 | 223 | 224 | 225 | YES 226 | 227 | 228 | YES 229 | 230 | 231 | 232 | 233 | YES 234 | 235 | 236 | YES 237 | 238 | 239 | 240 | 16 241 | 242 | 243 | 244 | YES 245 | 246 | RootViewController 247 | UITableViewController 248 | 249 | IBProjectSource 250 | Classes/RootViewController.h 251 | 252 | 253 | 254 | UIWindow 255 | UIView 256 | 257 | IBUserSource 258 | 259 | 260 | 261 | 262 | TreeListAppDelegate 263 | NSObject 264 | 265 | YES 266 | 267 | YES 268 | navigationController 269 | window 270 | 271 | 272 | YES 273 | UINavigationController 274 | UIWindow 275 | 276 | 277 | 278 | YES 279 | 280 | YES 281 | navigationController 282 | window 283 | 284 | 285 | YES 286 | 287 | navigationController 288 | UINavigationController 289 | 290 | 291 | window 292 | UIWindow 293 | 294 | 295 | 296 | 297 | IBProjectSource 298 | Classes/TreeListAppDelegate.h 299 | 300 | 301 | 302 | 303 | YES 304 | 305 | NSObject 306 | 307 | IBFrameworkSource 308 | Foundation.framework/Headers/NSError.h 309 | 310 | 311 | 312 | NSObject 313 | 314 | IBFrameworkSource 315 | Foundation.framework/Headers/NSFileManager.h 316 | 317 | 318 | 319 | NSObject 320 | 321 | IBFrameworkSource 322 | Foundation.framework/Headers/NSKeyValueCoding.h 323 | 324 | 325 | 326 | NSObject 327 | 328 | IBFrameworkSource 329 | Foundation.framework/Headers/NSKeyValueObserving.h 330 | 331 | 332 | 333 | NSObject 334 | 335 | IBFrameworkSource 336 | Foundation.framework/Headers/NSKeyedArchiver.h 337 | 338 | 339 | 340 | NSObject 341 | 342 | IBFrameworkSource 343 | Foundation.framework/Headers/NSObject.h 344 | 345 | 346 | 347 | NSObject 348 | 349 | IBFrameworkSource 350 | Foundation.framework/Headers/NSRunLoop.h 351 | 352 | 353 | 354 | NSObject 355 | 356 | IBFrameworkSource 357 | Foundation.framework/Headers/NSThread.h 358 | 359 | 360 | 361 | NSObject 362 | 363 | IBFrameworkSource 364 | Foundation.framework/Headers/NSURL.h 365 | 366 | 367 | 368 | NSObject 369 | 370 | IBFrameworkSource 371 | Foundation.framework/Headers/NSURLConnection.h 372 | 373 | 374 | 375 | NSObject 376 | 377 | IBFrameworkSource 378 | UIKit.framework/Headers/UIAccessibility.h 379 | 380 | 381 | 382 | NSObject 383 | 384 | IBFrameworkSource 385 | UIKit.framework/Headers/UINibLoading.h 386 | 387 | 388 | 389 | NSObject 390 | 391 | IBFrameworkSource 392 | UIKit.framework/Headers/UIResponder.h 393 | 394 | 395 | 396 | UIApplication 397 | UIResponder 398 | 399 | IBFrameworkSource 400 | UIKit.framework/Headers/UIApplication.h 401 | 402 | 403 | 404 | UIBarButtonItem 405 | UIBarItem 406 | 407 | IBFrameworkSource 408 | UIKit.framework/Headers/UIBarButtonItem.h 409 | 410 | 411 | 412 | UIBarItem 413 | NSObject 414 | 415 | IBFrameworkSource 416 | UIKit.framework/Headers/UIBarItem.h 417 | 418 | 419 | 420 | UINavigationBar 421 | UIView 422 | 423 | IBFrameworkSource 424 | UIKit.framework/Headers/UINavigationBar.h 425 | 426 | 427 | 428 | UINavigationController 429 | UIViewController 430 | 431 | IBFrameworkSource 432 | UIKit.framework/Headers/UINavigationController.h 433 | 434 | 435 | 436 | UINavigationItem 437 | NSObject 438 | 439 | 440 | 441 | UIResponder 442 | NSObject 443 | 444 | 445 | 446 | UISearchBar 447 | UIView 448 | 449 | IBFrameworkSource 450 | UIKit.framework/Headers/UISearchBar.h 451 | 452 | 453 | 454 | UISearchDisplayController 455 | NSObject 456 | 457 | IBFrameworkSource 458 | UIKit.framework/Headers/UISearchDisplayController.h 459 | 460 | 461 | 462 | UITableViewController 463 | UIViewController 464 | 465 | IBFrameworkSource 466 | UIKit.framework/Headers/UITableViewController.h 467 | 468 | 469 | 470 | UIView 471 | 472 | IBFrameworkSource 473 | UIKit.framework/Headers/UITextField.h 474 | 475 | 476 | 477 | UIView 478 | UIResponder 479 | 480 | IBFrameworkSource 481 | UIKit.framework/Headers/UIView.h 482 | 483 | 484 | 485 | UIViewController 486 | 487 | 488 | 489 | UIViewController 490 | 491 | IBFrameworkSource 492 | UIKit.framework/Headers/UIPopoverController.h 493 | 494 | 495 | 496 | UIViewController 497 | 498 | IBFrameworkSource 499 | UIKit.framework/Headers/UISplitViewController.h 500 | 501 | 502 | 503 | UIViewController 504 | 505 | IBFrameworkSource 506 | UIKit.framework/Headers/UITabBarController.h 507 | 508 | 509 | 510 | UIViewController 511 | UIResponder 512 | 513 | IBFrameworkSource 514 | UIKit.framework/Headers/UIViewController.h 515 | 516 | 517 | 518 | UIWindow 519 | UIView 520 | 521 | IBFrameworkSource 522 | UIKit.framework/Headers/UIWindow.h 523 | 524 | 525 | 526 | 527 | 0 528 | IBCocoaTouchFramework 529 | 530 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 531 | 532 | 533 | 534 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 535 | 536 | 537 | YES 538 | TreeList.xcodeproj 539 | 3 540 | 112 541 | 542 | 543 | -------------------------------------------------------------------------------- /Resources-iPad/MainWindow-iPad.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1056 5 | 10J869 6 | 851 7 | 1038.35 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 141 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBIPadFramework 35 | 36 | 37 | IBFirstResponder 38 | IBIPadFramework 39 | 40 | 41 | IBIPadFramework 42 | 43 | 44 | 45 | 1316 46 | 47 | {768, 1024} 48 | 49 | 50 | 1 51 | MSAxIDEAA 52 | 53 | NO 54 | NO 55 | 56 | 2 57 | 58 | IBIPadFramework 59 | YES 60 | 61 | 62 | 63 | 64 | 1 65 | 66 | IBIPadFramework 67 | NO 68 | 69 | 70 | 256 71 | {0, 0} 72 | NO 73 | YES 74 | YES 75 | IBIPadFramework 76 | 77 | 78 | YES 79 | 80 | 81 | IBIPadFramework 82 | 83 | 84 | RootViewController 85 | 86 | 87 | 1 88 | 89 | IBIPadFramework 90 | NO 91 | 92 | 93 | 94 | 95 | 96 | 97 | YES 98 | 99 | 100 | delegate 101 | 102 | 103 | 104 | 4 105 | 106 | 107 | 108 | window 109 | 110 | 111 | 112 | 5 113 | 114 | 115 | 116 | navigationController 117 | 118 | 119 | 120 | 15 121 | 122 | 123 | 124 | 125 | YES 126 | 127 | 0 128 | 129 | 130 | 131 | 132 | 133 | 2 134 | 135 | 136 | YES 137 | 138 | 139 | 140 | 141 | -1 142 | 143 | 144 | File's Owner 145 | 146 | 147 | 3 148 | 149 | 150 | 151 | 152 | -2 153 | 154 | 155 | 156 | 157 | 9 158 | 159 | 160 | YES 161 | 162 | 163 | 164 | 165 | 166 | 167 | 11 168 | 169 | 170 | 171 | 172 | 13 173 | 174 | 175 | YES 176 | 177 | 178 | 179 | 180 | 181 | 14 182 | 183 | 184 | 185 | 186 | 187 | 188 | YES 189 | 190 | YES 191 | -1.CustomClassName 192 | -2.CustomClassName 193 | 11.IBPluginDependency 194 | 13.CustomClassName 195 | 13.IBLastUsedUIStatusBarStylesToTargetRuntimesMap 196 | 13.IBPluginDependency 197 | 2.IBAttributePlaceholdersKey 198 | 2.IBEditorWindowLastContentRect 199 | 2.IBLastUsedUIStatusBarStylesToTargetRuntimesMap 200 | 2.IBPluginDependency 201 | 3.CustomClassName 202 | 3.IBPluginDependency 203 | 9.IBEditorWindowLastContentRect 204 | 9.IBLastUsedUIStatusBarStylesToTargetRuntimesMap 205 | 9.IBPluginDependency 206 | 207 | 208 | YES 209 | UIApplication 210 | UIResponder 211 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 212 | RootViewController 213 | 214 | IBCocoaTouchFramework 215 | 216 | 217 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 218 | 219 | YES 220 | 221 | 222 | YES 223 | 224 | 225 | {{673, 132}, {768, 1024}} 226 | 227 | IBCocoaTouchFramework 228 | 229 | 230 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 231 | TreeListAppDelegate 232 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 233 | {{186, 376}, {320, 480}} 234 | 235 | IBCocoaTouchFramework 236 | 237 | 238 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 239 | 240 | 241 | 242 | YES 243 | 244 | 245 | YES 246 | 247 | 248 | 249 | 250 | YES 251 | 252 | 253 | YES 254 | 255 | 256 | 257 | 16 258 | 259 | 260 | 261 | YES 262 | 263 | NSObject 264 | 265 | IBProjectSource 266 | NSObject+SBJSON.h 267 | 268 | 269 | 270 | NSObject 271 | 272 | IBProjectSource 273 | SBJsonWriter.h 274 | 275 | 276 | 277 | RootViewController 278 | UITableViewController 279 | 280 | IBProjectSource 281 | Classes/RootViewController.h 282 | 283 | 284 | 285 | TreeListAppDelegate 286 | NSObject 287 | 288 | YES 289 | 290 | YES 291 | navigationController 292 | window 293 | 294 | 295 | YES 296 | UINavigationController 297 | UIWindow 298 | 299 | 300 | 301 | YES 302 | 303 | YES 304 | navigationController 305 | window 306 | 307 | 308 | YES 309 | 310 | navigationController 311 | UINavigationController 312 | 313 | 314 | window 315 | UIWindow 316 | 317 | 318 | 319 | 320 | IBProjectSource 321 | Classes/TreeListAppDelegate.h 322 | 323 | 324 | 325 | UIWindow 326 | UIView 327 | 328 | IBUserSource 329 | 330 | 331 | 332 | 333 | 334 | YES 335 | 336 | NSObject 337 | 338 | IBFrameworkSource 339 | Foundation.framework/Headers/NSError.h 340 | 341 | 342 | 343 | NSObject 344 | 345 | IBFrameworkSource 346 | Foundation.framework/Headers/NSFileManager.h 347 | 348 | 349 | 350 | NSObject 351 | 352 | IBFrameworkSource 353 | Foundation.framework/Headers/NSKeyValueCoding.h 354 | 355 | 356 | 357 | NSObject 358 | 359 | IBFrameworkSource 360 | Foundation.framework/Headers/NSKeyValueObserving.h 361 | 362 | 363 | 364 | NSObject 365 | 366 | IBFrameworkSource 367 | Foundation.framework/Headers/NSKeyedArchiver.h 368 | 369 | 370 | 371 | NSObject 372 | 373 | IBFrameworkSource 374 | Foundation.framework/Headers/NSObject.h 375 | 376 | 377 | 378 | NSObject 379 | 380 | IBFrameworkSource 381 | Foundation.framework/Headers/NSRunLoop.h 382 | 383 | 384 | 385 | NSObject 386 | 387 | IBFrameworkSource 388 | Foundation.framework/Headers/NSThread.h 389 | 390 | 391 | 392 | NSObject 393 | 394 | IBFrameworkSource 395 | Foundation.framework/Headers/NSURL.h 396 | 397 | 398 | 399 | NSObject 400 | 401 | IBFrameworkSource 402 | Foundation.framework/Headers/NSURLConnection.h 403 | 404 | 405 | 406 | NSObject 407 | 408 | IBFrameworkSource 409 | UIKit.framework/Headers/UIAccessibility.h 410 | 411 | 412 | 413 | NSObject 414 | 415 | IBFrameworkSource 416 | UIKit.framework/Headers/UINibLoading.h 417 | 418 | 419 | 420 | NSObject 421 | 422 | IBFrameworkSource 423 | UIKit.framework/Headers/UIResponder.h 424 | 425 | 426 | 427 | UIApplication 428 | UIResponder 429 | 430 | IBFrameworkSource 431 | UIKit.framework/Headers/UIApplication.h 432 | 433 | 434 | 435 | UIBarButtonItem 436 | UIBarItem 437 | 438 | IBFrameworkSource 439 | UIKit.framework/Headers/UIBarButtonItem.h 440 | 441 | 442 | 443 | UIBarItem 444 | NSObject 445 | 446 | IBFrameworkSource 447 | UIKit.framework/Headers/UIBarItem.h 448 | 449 | 450 | 451 | UINavigationBar 452 | UIView 453 | 454 | IBFrameworkSource 455 | UIKit.framework/Headers/UINavigationBar.h 456 | 457 | 458 | 459 | UINavigationController 460 | UIViewController 461 | 462 | IBFrameworkSource 463 | UIKit.framework/Headers/UINavigationController.h 464 | 465 | 466 | 467 | UINavigationItem 468 | NSObject 469 | 470 | 471 | 472 | UIResponder 473 | NSObject 474 | 475 | 476 | 477 | UISearchBar 478 | UIView 479 | 480 | IBFrameworkSource 481 | UIKit.framework/Headers/UISearchBar.h 482 | 483 | 484 | 485 | UISearchDisplayController 486 | NSObject 487 | 488 | IBFrameworkSource 489 | UIKit.framework/Headers/UISearchDisplayController.h 490 | 491 | 492 | 493 | UITableViewController 494 | UIViewController 495 | 496 | IBFrameworkSource 497 | UIKit.framework/Headers/UITableViewController.h 498 | 499 | 500 | 501 | UIView 502 | 503 | IBFrameworkSource 504 | UIKit.framework/Headers/UIPrintFormatter.h 505 | 506 | 507 | 508 | UIView 509 | 510 | IBFrameworkSource 511 | UIKit.framework/Headers/UITextField.h 512 | 513 | 514 | 515 | UIView 516 | UIResponder 517 | 518 | IBFrameworkSource 519 | UIKit.framework/Headers/UIView.h 520 | 521 | 522 | 523 | UIViewController 524 | 525 | 526 | 527 | UIViewController 528 | 529 | IBFrameworkSource 530 | UIKit.framework/Headers/UIPopoverController.h 531 | 532 | 533 | 534 | UIViewController 535 | 536 | IBFrameworkSource 537 | UIKit.framework/Headers/UISplitViewController.h 538 | 539 | 540 | 541 | UIViewController 542 | 543 | IBFrameworkSource 544 | UIKit.framework/Headers/UITabBarController.h 545 | 546 | 547 | 548 | UIViewController 549 | UIResponder 550 | 551 | IBFrameworkSource 552 | UIKit.framework/Headers/UIViewController.h 553 | 554 | 555 | 556 | UIWindow 557 | UIView 558 | 559 | IBFrameworkSource 560 | UIKit.framework/Headers/UIWindow.h 561 | 562 | 563 | 564 | 565 | 0 566 | IBIPadFramework 567 | 568 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 569 | 570 | 571 | 572 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 573 | 574 | 575 | YES 576 | ../TreeList.xcodeproj 577 | 3 578 | 141 579 | 580 | 581 | --------------------------------------------------------------------------------