├── .gitignore ├── Unused ├── Unused │ ├── en.lproj │ │ ├── InfoPlist.strings │ │ ├── Credits.rtfd │ │ │ └── TXT.rtf │ │ ├── Localizable.strings │ │ └── MainMenu.xib │ ├── fr.lproj │ │ ├── InfoPlist.strings │ │ ├── Localizable.strings │ │ └── Credits.rtfd │ │ │ └── TXT.rtf │ ├── Icon.icns │ ├── Images.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── icon_16x16.png │ │ │ ├── icon_32x32.png │ │ │ ├── icon_128x128.png │ │ │ ├── icon_256x256-1.png │ │ │ ├── icon_256x256.png │ │ │ ├── icon_32x32-1.png │ │ │ ├── icon_512x512-1.png │ │ │ ├── icon_512x512.png │ │ │ └── Contents.json │ ├── Unused-Prefix.pch │ ├── main.m │ ├── CONTRIBUTORS │ ├── Unused-Info.plist │ ├── FileUtil.h │ ├── FileUtil.m │ ├── Searcher.h │ ├── UnusedAppDelegate.h │ ├── UnusedAppDelegate.m │ └── Searcher.m └── Unused.xcodeproj │ ├── xcuserdata │ └── jeff.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── Unused.xcscheme │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── jeff.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── project.pbxproj └── README /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | xcuserdata 3 | *.xccheckout 4 | -------------------------------------------------------------------------------- /Unused/Unused/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Unused/Unused/fr.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Unused/Unused/Icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffhodnett/Unused/HEAD/Unused/Unused/Icon.icns -------------------------------------------------------------------------------- /Unused/Unused/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Search */ 3 | "Search" = "Fouille"; 4 | "Searching" = "Fouille..."; 5 | -------------------------------------------------------------------------------- /Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffhodnett/Unused/HEAD/Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffhodnett/Unused/HEAD/Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffhodnett/Unused/HEAD/Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_256x256-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffhodnett/Unused/HEAD/Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_256x256-1.png -------------------------------------------------------------------------------- /Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffhodnett/Unused/HEAD/Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_32x32-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffhodnett/Unused/HEAD/Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_32x32-1.png -------------------------------------------------------------------------------- /Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_512x512-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffhodnett/Unused/HEAD/Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_512x512-1.png -------------------------------------------------------------------------------- /Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffhodnett/Unused/HEAD/Unused/Unused/Images.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /Unused/Unused.xcodeproj/xcuserdata/jeff.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Unused/Unused/Unused-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Unused' target in the 'Unused' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /Unused/Unused.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Unused/Unused.xcodeproj/project.xcworkspace/xcuserdata/jeff.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeffhodnett/Unused/HEAD/Unused/Unused.xcodeproj/project.xcworkspace/xcuserdata/jeff.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Unused/Unused/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Unused 4 | // 5 | // Created by Jeff Hodnett on 19/11/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **)argv); 14 | } 15 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Unused - Mac App 2 | ================ 3 | 4 | version 1.0 5 | 6 | Created by: Jeff Hodnett 7 | jefers@gmail.com 8 | http://www.jeffhodnett.com 9 | 10 | Use this useful utility tool to check what image resources are not being used in your Xcode projects. 11 | Very useful to reduce your bundle size by showing you what images are not used! 12 | 13 | Full project info here: 14 | http://jeffhodnett.github.io/Unused/ 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Unused/Unused/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | 2 | THANK YOU! 3 | 4 | Many thanks for all the hard work of the contributors, without your interest this open source project it would not continue to improve. Please add your name to the list of contributors below so you can get the credit you deserve. 5 | 6 | Thanks, 7 | Jeff 8 | @jeffhodnett 9 | 10 | 11 | CONTRIBUTORS: 12 | 13 | - Fábio Bernardo 14 | - Andrey Toropchin 15 | - Iain Delaney 16 | - BrianSemiglia 17 | - guykogus 18 | - RolandasRazma 19 | - neoman-v 20 | - cytryn 21 | - Asynchrony Dev 22 | - laughingMan -------------------------------------------------------------------------------- /Unused/Unused.xcodeproj/xcuserdata/jeff.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Unused.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1F55B4A21478097A008A4B0E 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Unused/Unused/en.lproj/Credits.rtfd/TXT.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1344\cocoasubrtf720 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 Menlo-Regular;} 3 | {\colortbl;\red255\green255\blue255;\red14\green14\blue255;} 4 | \paperw11900\paperh16840\vieww9600\viewh8400\viewkind0 5 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 6 | 7 | \f0\b\fs24 \cf0 Developed by:\ 8 | 9 | \b0 Jeff Hodnett\ 10 | http://www.jeffhodnett.com\ 11 | 12 | \b \ 13 | \pard\tx577\pardeftab577\pardirnatural 14 | {\field{\*\fldinst{HYPERLINK "https://github.com/jeffhodnett/Unused"}}{\fldrslt 15 | \f1\b0 \cf2 \CocoaLigature0 https://github.com/jeffhodnett/Unused}}} -------------------------------------------------------------------------------- /Unused/Unused/fr.lproj/Credits.rtfd/TXT.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1344\cocoasubrtf720 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fnil\fcharset0 Menlo-Regular;} 3 | {\colortbl;\red255\green255\blue255;\red14\green14\blue255;} 4 | \paperw11900\paperh16840\vieww9600\viewh8400\viewkind0 5 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 6 | 7 | \f0\b\fs24 \cf0 Developed by:\ 8 | 9 | \b0 Jeff Hodnett\ 10 | http://www.jeffhodnett.com\ 11 | 12 | \b \ 13 | \pard\tx577\pardeftab577\pardirnatural 14 | {\field{\*\fldinst{HYPERLINK "https://github.com/jeffhodnett/Unused"}}{\fldrslt 15 | \f1\b0 \cf2 \CocoaLigature0 https://github.com/jeffhodnett/Unused}}} -------------------------------------------------------------------------------- /Unused/Unused/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Search */ 3 | "Search" = "Search"; 4 | "Searching" = "Searching..."; 5 | "CompletedResultMessage" = "Completed - Found %ld - Size %@"; 6 | 7 | /* Export */ 8 | "ExportSummaryTitle" = "Unused Files in project %@\n\n"; 9 | "ExportCompleteTitle" = "Export Complete"; 10 | "ExportCompleteSubtitle" = "The results have been exported successfully"; 11 | "ExportErrorTitle" = "Export Error"; 12 | "ExportErrorSubtitle" = "There was an error exporting the results"; 13 | 14 | /* Errors */ 15 | "MissingPathErrorTitle" = "No Project Folder Selected"; 16 | "InvalidPathErrorTitle" = "Invalid Project Folder"; 17 | "ProjectFolderPathErrorMessage" = "\nPlease select a valid project folder"; 18 | -------------------------------------------------------------------------------- /Unused/Unused/Unused-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.jeffhodnett.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSApplicationCategoryType 24 | public.app-category.utilities 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2013 Seamonster Ltd. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /Unused/Unused/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_32x32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32-1.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "idiom" : "mac", 23 | "size" : "32x32", 24 | "scale" : "2x" 25 | }, 26 | { 27 | "size" : "128x128", 28 | "idiom" : "mac", 29 | "filename" : "icon_128x128.png", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "size" : "128x128", 34 | "idiom" : "mac", 35 | "filename" : "icon_256x256-1.png", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "size" : "256x256", 40 | "idiom" : "mac", 41 | "filename" : "icon_256x256.png", 42 | "scale" : "1x" 43 | }, 44 | { 45 | "size" : "256x256", 46 | "idiom" : "mac", 47 | "filename" : "icon_512x512.png", 48 | "scale" : "2x" 49 | }, 50 | { 51 | "size" : "512x512", 52 | "idiom" : "mac", 53 | "filename" : "icon_512x512-1.png", 54 | "scale" : "1x" 55 | }, 56 | { 57 | "idiom" : "mac", 58 | "size" : "512x512", 59 | "scale" : "2x" 60 | } 61 | ], 62 | "info" : { 63 | "version" : 1, 64 | "author" : "xcode" 65 | } 66 | } -------------------------------------------------------------------------------- /Unused/Unused/FileUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // FileUtil.h 3 | // Unused 4 | // https://github.com/jeffhodnett/Unused 5 | // 6 | // Copyright (c) 2015 Jeff Hodnett 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | 27 | #import 28 | 29 | /** 30 | * File util helper class 31 | */ 32 | @interface FileUtil : NSObject 33 | 34 | /** 35 | * Return the nice formatted string for a file size 36 | * i.e input = 1024 output = 1 KB 37 | * 38 | * @param fileSize The file size integer 39 | * 40 | * @return The formatted string descriptor for the size value 41 | */ 42 | + (NSString *)stringFromFileSize:(int)fileSize; 43 | 44 | /** 45 | * Return all the image paths in the provided directory 46 | * 47 | * This includes searching for image files like 48 | * .jpg, .jpeg, .png, .gif 49 | * 50 | * @param directoryPath The search path 51 | * 52 | * @return The array of image paths 53 | */ 54 | + (NSArray *)imageFilesInDirectory:(NSString *)directoryPath; 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Unused/Unused.xcodeproj/xcuserdata/jeff.xcuserdatad/xcschemes/Unused.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 53 | 54 | 60 | 61 | 62 | 63 | 64 | 65 | 73 | 74 | 80 | 81 | 82 | 83 | 85 | 86 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Unused/Unused/FileUtil.m: -------------------------------------------------------------------------------- 1 | // 2 | // FileUtil.m 3 | // Unused 4 | // https://github.com/jeffhodnett/Unused 5 | // 6 | // Copyright (c) 2015 Jeff Hodnett 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | 27 | #import "FileUtil.h" 28 | 29 | @implementation FileUtil 30 | 31 | + (NSString *)stringFromFileSize:(int)fileSize { 32 | if (fileSize < 1023) { 33 | return([NSString stringWithFormat:@"%i bytes", fileSize]); 34 | } 35 | 36 | float floatSize = fileSize / 1024; 37 | if (floatSize < 1023) { 38 | return([NSString stringWithFormat:@"%1.1f KB", floatSize]); 39 | } 40 | 41 | floatSize = floatSize / 1024; 42 | if (floatSize < 1023) { 43 | return([NSString stringWithFormat:@"%1.1f MB", floatSize]); 44 | } 45 | 46 | floatSize = floatSize / 1024; 47 | return([NSString stringWithFormat:@"%1.1f GB",floatSize]); 48 | } 49 | 50 | + (NSArray *)imageFilesInDirectory:(NSString *)directoryPath { 51 | 52 | NSMutableArray *images = [NSMutableArray array]; 53 | 54 | // jpg 55 | NSArray *jpg = [self searchDirectory:directoryPath forFiletype:@"jpg"]; 56 | [images addObjectsFromArray:jpg]; 57 | 58 | // jpeg 59 | NSArray *jpeg = [self searchDirectory:directoryPath forFiletype:@"jpeg"]; 60 | [images addObjectsFromArray:jpeg]; 61 | 62 | // png 63 | NSArray *png = [self searchDirectory:directoryPath forFiletype:@"png"]; 64 | [images addObjectsFromArray:png]; 65 | 66 | // gif 67 | NSArray *gif = [self searchDirectory:directoryPath forFiletype:@"gif"]; 68 | [images addObjectsFromArray:gif]; 69 | 70 | return images; 71 | } 72 | 73 | + (NSArray *)searchDirectory:(NSString *)directoryPath forFiletype:(NSString *)filetype { 74 | // Create a find task 75 | NSTask *task = [[NSTask alloc] init]; 76 | [task setLaunchPath: @"/usr/bin/find"]; 77 | 78 | // Search for all png files 79 | NSArray *argvals = [NSArray arrayWithObjects:directoryPath,@"-name",[NSString stringWithFormat:@"*.%@", filetype], nil]; 80 | [task setArguments: argvals]; 81 | 82 | NSPipe *pipe = [NSPipe pipe]; 83 | [task setStandardOutput: pipe]; 84 | NSFileHandle *file = [pipe fileHandleForReading]; 85 | 86 | // Run task 87 | [task launch]; 88 | 89 | // Read the response 90 | NSData *data = [file readDataToEndOfFile]; 91 | NSString *string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; 92 | 93 | // See if we can create a lines array 94 | NSArray *lines = [string componentsSeparatedByString:@"\n"]; 95 | 96 | return lines; 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /Unused/Unused/Searcher.h: -------------------------------------------------------------------------------- 1 | // 2 | // Searcher.h 3 | // Unused 4 | // https://github.com/jeffhodnett/Unused 5 | // 6 | // Copyright (c) 2015 Jeff Hodnett 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | 27 | #import 28 | 29 | @class Searcher; 30 | 31 | /** 32 | * The searcher delegate 33 | */ 34 | @protocol SearcherDelegate 35 | 36 | @optional 37 | /** 38 | * The searcher did begin searching 39 | * 40 | * @param searcher The searcher object 41 | */ 42 | - (void)searcherDidStartSearch:(Searcher *)searcher; 43 | 44 | /** 45 | * The searcher did find an unused image during its search 46 | * 47 | * @param searcher The searcher object 48 | * @param imagePath The unused image path 49 | */ 50 | - (void)searcher:(Searcher *)searcher didFindUnusedImage:(NSString *)imagePath; 51 | 52 | /** 53 | * The searcher did finish searching 54 | * 55 | * @param searcher The searcher object 56 | * @param results The unused image path results 57 | */ 58 | - (void)searcher:(Searcher *)searcher didFinishSearch:(NSArray *)results; 59 | 60 | @end 61 | 62 | /** 63 | * The searcher class 64 | * Use this object to search for un-used image files in your xcode projects 65 | */ 66 | @interface Searcher : NSObject 67 | 68 | /** 69 | * The searcher delegate 70 | */ 71 | @property (assign) id delegate; 72 | 73 | /** 74 | * The project search path 75 | */ 76 | @property (copy) NSString *projectPath; 77 | 78 | /** 79 | * Include .m files in the search 80 | */ 81 | @property (nonatomic) BOOL mSearch; 82 | 83 | /** 84 | * Include .xib files in the search 85 | */ 86 | @property (nonatomic) BOOL xibSearch; 87 | 88 | /** 89 | * Include .storyboard files in the search 90 | */ 91 | @property (nonatomic) BOOL storyboardSearch; 92 | 93 | /** 94 | * Include .cpp files in the search 95 | */ 96 | @property (nonatomic) BOOL cppSearch; 97 | 98 | /** 99 | * Include .h files in the search 100 | */ 101 | @property (nonatomic) BOOL headerSearch; 102 | 103 | /** 104 | * Include .html files in the search 105 | */ 106 | @property (nonatomic) BOOL htmlSearch; 107 | 108 | /** 109 | * Include .mm files in the search 110 | */ 111 | @property (nonatomic) BOOL mmSearch; 112 | 113 | /** 114 | * Include .plist files in the search 115 | */ 116 | @property (nonatomic) BOOL plistSearch; 117 | 118 | /** 119 | * Include .css files in the search 120 | */ 121 | @property (nonatomic) BOOL cssSearch; 122 | 123 | /** 124 | * Include .swift files in the search 125 | */ 126 | @property (nonatomic) BOOL swiftSearch; 127 | 128 | /** 129 | * Include image enum variant filtering in the search 130 | */ 131 | @property (nonatomic) BOOL enumFilter; 132 | 133 | /** 134 | * Start the search 135 | */ 136 | - (void)start; 137 | 138 | /** 139 | * Stop the search 140 | */ 141 | - (void)stop; 142 | 143 | @end 144 | -------------------------------------------------------------------------------- /Unused/Unused/UnusedAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // UnusedAppDelegate.h 3 | // Unused 4 | // A Mac utility to show you unused resources in your xcode projects 5 | // https://github.com/jeffhodnett/Unused 6 | // 7 | // Copyright (c) 2015 Jeff Hodnett 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in all 17 | // copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | // SOFTWARE. 26 | // 27 | 28 | #import 29 | 30 | /** 31 | * The application delegate 32 | */ 33 | @interface UnusedAppDelegate : NSObject 34 | 35 | // ------ Outlets ------ 36 | /** 37 | * The main window 38 | */ 39 | @property (assign) IBOutlet NSWindow *window; 40 | 41 | /** 42 | * The results table view 43 | */ 44 | @property (assign) IBOutlet NSTableView *resultsTableView; 45 | 46 | /** 47 | * The loading indicator view 48 | */ 49 | @property (assign) IBOutlet NSProgressIndicator *processIndicator; 50 | 51 | /** 52 | * The status text label 53 | */ 54 | @property (assign) IBOutlet NSTextField *statusLabel; 55 | 56 | /** 57 | * The browse button 58 | */ 59 | @property (assign) IBOutlet NSButton *browseButton; 60 | 61 | /** 62 | * The search path text field 63 | */ 64 | @property (assign) IBOutlet NSTextField *pathTextField; 65 | 66 | /** 67 | * The search action button 68 | */ 69 | @property (assign) IBOutlet NSButton *searchButton; 70 | 71 | /** 72 | * The export button 73 | */ 74 | @property (assign) IBOutlet NSButton *exportButton; 75 | 76 | /** 77 | * The .m file checkbox 78 | */ 79 | @property (assign) IBOutlet NSButton *mCheckbox; 80 | 81 | /** 82 | * The .xib file checkbox 83 | */ 84 | @property (assign) IBOutlet NSButton *xibCheckbox; 85 | 86 | /** 87 | * The .storyboard file checkbox 88 | */ 89 | @property (assign) IBOutlet NSButton *sbCheckbox; 90 | 91 | /** 92 | * The .cpp file checkbox 93 | */ 94 | @property (assign) IBOutlet NSButton *cppCheckbox; 95 | 96 | /** 97 | * The .h file checkbox 98 | */ 99 | @property (assign) IBOutlet NSButton *headerCheckbox; 100 | 101 | /** 102 | * The .html file checkbox 103 | */ 104 | @property (assign) IBOutlet NSButton *htmlCheckbox; 105 | 106 | /** 107 | * The .mm file checkbox 108 | */ 109 | @property (assign) IBOutlet NSButton *mmCheckbox; 110 | 111 | /** 112 | * The .plist file checkbox 113 | */ 114 | @property (assign) IBOutlet NSButton *plistCheckbox; 115 | 116 | /** 117 | * The .css file checkbox 118 | */ 119 | @property (assign) IBOutlet NSButton *cssCheckbox; 120 | 121 | /** 122 | * The .swift file checkbox 123 | */ 124 | @property (assign) IBOutlet NSButton *swiftCheckbox; 125 | 126 | /** 127 | * The enum checkbox 128 | */ 129 | @property (assign) IBOutlet NSButton *enumCheckbox; 130 | 131 | // ------ Actions ------ 132 | /** 133 | * The browse for xcode project action 134 | * 135 | * @param sender The browse button 136 | */ 137 | - (IBAction)browseButtonSelected:(id)sender; 138 | 139 | /** 140 | * Start the search process 141 | * 142 | * @param sender The search button 143 | */ 144 | - (IBAction)startSearch:(id)sender; 145 | 146 | /** 147 | * Export the results to a file 148 | * 149 | * @param sender The export button 150 | */ 151 | - (IBAction)exportButtonSelected:(id)sender; 152 | 153 | @end 154 | -------------------------------------------------------------------------------- /Unused/Unused/UnusedAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // UnusedAppDelegate.m 3 | // Unused 4 | // https://github.com/jeffhodnett/Unused 5 | // 6 | // Copyright (c) 2015 Jeff Hodnett 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | 27 | #import "UnusedAppDelegate.h" 28 | #import "Searcher.h" 29 | #import "FileUtil.h" 30 | 31 | @interface UnusedAppDelegate () 32 | 33 | @property (nonatomic, strong) NSMutableArray *results; 34 | @property (nonatomic, strong) Searcher *searcher; 35 | 36 | // Handle the ui updates 37 | - (void)setUIEnabled:(BOOL)state; 38 | 39 | @end 40 | 41 | // Constant strings 42 | static NSString *const kTableColumnImageIcon = @"ImageIcon"; 43 | static NSString *const kTableColumnImageShortName = @"ImageShortName"; 44 | 45 | @implementation UnusedAppDelegate 46 | 47 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 48 | // Setup the results array 49 | _results = [[NSMutableArray alloc] init]; 50 | 51 | // Setup double click 52 | [_resultsTableView setDoubleAction:@selector(tableViewDoubleClicked)]; 53 | 54 | // Setup labels 55 | [_statusLabel setTextColor:[NSColor lightGrayColor]]; 56 | 57 | // Setup search button 58 | [_searchButton setBezelStyle:NSRoundedBezelStyle]; 59 | [_searchButton setKeyEquivalent:@"\r"]; 60 | 61 | // Setup the searcher 62 | self.searcher = [[Searcher alloc] init]; 63 | self.searcher.delegate = self; 64 | } 65 | 66 | #pragma mark - Actions 67 | - (IBAction)browseButtonSelected:(id)sender { 68 | // Show an open panel 69 | NSOpenPanel *openPanel = [NSOpenPanel openPanel]; 70 | [openPanel setCanChooseDirectories:YES]; 71 | [openPanel setCanChooseFiles:NO]; 72 | 73 | BOOL okButtonPressed = ([openPanel runModal] == NSModalResponseOK); 74 | if (okButtonPressed) { 75 | // Update the path text field 76 | NSString *path = [[openPanel directoryURL] path]; 77 | [self.pathTextField setStringValue:path]; 78 | } 79 | } 80 | 81 | - (IBAction)exportButtonSelected:(id)sender { 82 | NSSavePanel *save = [NSSavePanel savePanel]; 83 | [save setAllowedFileTypes:[NSArray arrayWithObject:@"txt"]]; 84 | 85 | BOOL okButtonPressed = ([save runModal] == NSModalResponseOK); 86 | if (okButtonPressed) { 87 | NSString *selectedFile = [[save URL] path]; 88 | 89 | NSMutableString *outputResults = [[NSMutableString alloc] init]; 90 | NSString *projectPath = [self.pathTextField stringValue]; 91 | [outputResults appendFormat:NSLocalizedString(@"ExportSummaryTitle", @""), projectPath]; 92 | 93 | for (NSString *path in _results) { 94 | [outputResults appendFormat:@"%@\n",path]; 95 | } 96 | 97 | // Output 98 | NSError *writeError = nil; 99 | [outputResults writeToFile:selectedFile atomically:YES encoding:NSUTF8StringEncoding error:&writeError]; 100 | 101 | // Check write result 102 | if (writeError == nil) { 103 | [self showAlertWithStyle:NSInformationalAlertStyle title:NSLocalizedString(@"ExportCompleteTitle", @"") subtitle:NSLocalizedString(@"ExportCompleteSubtitle", @"")]; 104 | } else { 105 | NSLog(@"Unused write error:: %@", writeError); 106 | [self showAlertWithStyle:NSCriticalAlertStyle title:NSLocalizedString(@"ExportErrorTitle", @"") subtitle:NSLocalizedString(@"ExportErrorSubtitle", @"")]; 107 | } 108 | } 109 | } 110 | 111 | - (IBAction)startSearch:(id)sender { 112 | // Check if user has selected or entered a path 113 | NSString *projectPath = [self.pathTextField stringValue]; 114 | BOOL isPathEmpty = [projectPath isEqualToString:@""]; 115 | if (isPathEmpty) { 116 | [self showAlertWithStyle:NSWarningAlertStyle title:NSLocalizedString(@"MissingPathErrorTitle", @"") subtitle:NSLocalizedString(@"ProjectFolderPathErrorMessage", @"")]; 117 | 118 | return; 119 | } 120 | 121 | // Check the path exists 122 | BOOL pathExists = [[NSFileManager defaultManager] fileExistsAtPath:projectPath]; 123 | if (!pathExists) { 124 | [self showAlertWithStyle:NSWarningAlertStyle title:NSLocalizedString(@"InvalidPathErrorTitle", @"") subtitle:NSLocalizedString(@"ProjectFolderPathErrorMessage", @"")]; 125 | 126 | return; 127 | } 128 | 129 | // Reset 130 | [self.results removeAllObjects]; 131 | [self.resultsTableView reloadData]; 132 | 133 | // Start the ui 134 | [self setUIEnabled:NO]; 135 | 136 | // Pass search folder 137 | self.searcher.projectPath = projectPath; 138 | 139 | // Pass settings 140 | self.searcher.mSearch = [self.mCheckbox state]; 141 | self.searcher.xibSearch = [self.xibCheckbox state]; 142 | self.searcher.storyboardSearch = [self.sbCheckbox state]; 143 | self.searcher.cppSearch = [self.cppCheckbox state]; 144 | self.searcher.headerSearch = [self.headerCheckbox state]; 145 | self.searcher.htmlSearch = [self.htmlCheckbox state]; 146 | self.searcher.mmSearch = [self.mmCheckbox state]; 147 | self.searcher.plistSearch = [self.plistCheckbox state]; 148 | self.searcher.cssSearch = [self.cssCheckbox state]; 149 | self.searcher.swiftSearch = [self.swiftCheckbox state]; 150 | self.searcher.enumFilter = [self.enumCheckbox state]; 151 | 152 | // Start the search 153 | [self.searcher start]; 154 | } 155 | 156 | #pragma mark - Helpers 157 | - (void)showAlertWithStyle:(NSAlertStyle)style title:(NSString *)title subtitle:(NSString *)subtitle { 158 | NSAlert *alert = [[NSAlert alloc] init]; 159 | alert.alertStyle = style; 160 | [alert setMessageText:title]; 161 | [alert setInformativeText:subtitle]; 162 | [alert runModal]; 163 | } 164 | 165 | - (void)scrollTableView:(NSTableView *)tableView toBottom:(BOOL)bottom { 166 | if (bottom) { 167 | NSInteger numberOfRows = [tableView numberOfRows]; 168 | if (numberOfRows > 0) { 169 | [tableView scrollRowToVisible:numberOfRows - 1]; 170 | } 171 | } else { 172 | [tableView scrollRowToVisible:0]; 173 | } 174 | } 175 | 176 | - (void)setUIEnabled:(BOOL)state { 177 | // Individual 178 | if (state) { 179 | [_searchButton setTitle:NSLocalizedString(@"Search", @"")]; 180 | [_searchButton setKeyEquivalent:@"\r"]; 181 | [_processIndicator stopAnimation:self]; 182 | } else { 183 | [self.searchButton setKeyEquivalent:@""]; 184 | [_processIndicator startAnimation:self]; 185 | [_statusLabel setStringValue:NSLocalizedString(@"Searching", @"")]; 186 | } 187 | 188 | // Button groups 189 | [_searchButton setEnabled:state]; 190 | [_processIndicator setHidden:state]; 191 | [_mCheckbox setEnabled:state]; 192 | [_xibCheckbox setEnabled:state]; 193 | [_sbCheckbox setEnabled:state]; 194 | [_cppCheckbox setEnabled:state]; 195 | [_mmCheckbox setEnabled:state]; 196 | [_headerCheckbox setEnabled:state]; 197 | [_htmlCheckbox setEnabled:state]; 198 | [_plistCheckbox setEnabled:state]; 199 | [_cssCheckbox setEnabled:state]; 200 | [_swiftCheckbox setEnabled:state]; 201 | [_browseButton setEnabled:state]; 202 | [_pathTextField setEnabled:state]; 203 | [_exportButton setHidden:!state]; 204 | } 205 | 206 | #pragma mark - 207 | - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { 208 | return [self.results count]; 209 | } 210 | 211 | - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex { 212 | // Get the unused image 213 | NSString *pngPath = [self.results objectAtIndex:rowIndex]; 214 | 215 | // Check the column 216 | NSString *columnIdentifier = [tableColumn identifier]; 217 | if ([columnIdentifier isEqualToString:kTableColumnImageIcon]) { 218 | return [[NSImage alloc] initByReferencingFile:pngPath]; 219 | } else if ([columnIdentifier isEqualToString:kTableColumnImageShortName]) { 220 | return [pngPath lastPathComponent]; 221 | } 222 | 223 | return pngPath; 224 | } 225 | 226 | - (void)tableViewDoubleClicked { 227 | // Open finder 228 | NSString *path = [self.results objectAtIndex:[self.resultsTableView clickedRow]]; 229 | [[NSWorkspace sharedWorkspace] selectFile:path inFileViewerRootedAtPath:nil]; 230 | } 231 | 232 | #pragma mark - 233 | - (void)searcherDidStartSearch:(Searcher *)searcher { 234 | } 235 | 236 | - (void)searcher:(Searcher *)searcher didFindUnusedImage:(NSString *)imagePath { 237 | 238 | // Add and reload 239 | [self.results addObject:imagePath]; 240 | 241 | // Reload 242 | [self.resultsTableView reloadData]; 243 | 244 | // Scroll to the bottom 245 | [self scrollTableView:self.resultsTableView toBottom:YES]; 246 | } 247 | 248 | - (void)searcher:(Searcher *)searcher didFinishSearch:(NSArray *)results { 249 | 250 | // Ensure all data is displayed 251 | [self.resultsTableView reloadData]; 252 | 253 | // Calculate how much file size we saved and update the label 254 | int fileSize = 0; 255 | for (NSString *path in _results) { 256 | fileSize += [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil] fileSize]; 257 | } 258 | [self.statusLabel setStringValue:[NSString stringWithFormat:NSLocalizedString(@"CompletedResultMessage", @""), (unsigned long)[_results count], [FileUtil stringFromFileSize:fileSize]]]; 259 | 260 | // Enable the ui 261 | [self setUIEnabled:YES]; 262 | } 263 | 264 | @end 265 | -------------------------------------------------------------------------------- /Unused/Unused/Searcher.m: -------------------------------------------------------------------------------- 1 | // 2 | // Searcher.m 3 | // Unused 4 | // https://github.com/jeffhodnett/Unused 5 | // 6 | // Copyright (c) 2015 Jeff Hodnett 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all 16 | // copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | // SOFTWARE. 25 | // 26 | 27 | #import "Searcher.h" 28 | #import "FileUtil.h" 29 | 30 | @interface Searcher () { 31 | @private 32 | 33 | // Arrays 34 | NSArray *_projectImageFiles; 35 | NSMutableArray *_results; 36 | NSMutableArray *_retinaImagePaths; 37 | 38 | NSOperationQueue *_queue; 39 | BOOL isSearching; 40 | 41 | // Stores the file data to avoid re-reading files, using a lock to make it thread-safe. 42 | NSMutableDictionary *_fileData; 43 | NSLock *_fileDataLock; 44 | } 45 | 46 | @end 47 | 48 | @implementation Searcher 49 | 50 | - (instancetype)init { 51 | if (self = [super init]) { 52 | 53 | // Setup the results array 54 | _results = [[NSMutableArray alloc] init]; 55 | 56 | // Setup the retina images array 57 | _retinaImagePaths = [[NSMutableArray alloc] init]; 58 | 59 | // Setup the queue 60 | _queue = [[NSOperationQueue alloc] init]; 61 | 62 | // Setup data lock 63 | _fileData = [NSMutableDictionary new]; 64 | _fileDataLock = [NSLock new]; 65 | } 66 | return self; 67 | } 68 | 69 | - (void)start { 70 | 71 | // Start the search 72 | NSInvocationOperation *searchOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(runImageSearch:) object:self.projectPath]; 73 | [_queue addOperation:searchOperation]; 74 | } 75 | 76 | - (void)stop { 77 | #warning implement me! 78 | } 79 | 80 | - (void)runImageSearch:(NSString *)searchPath { 81 | // Start the search 82 | if (self.delegate && [self.delegate respondsToSelector:@selector(searcherDidStartSearch:)]) { 83 | [self.delegate searcherDidStartSearch:self]; 84 | } 85 | 86 | // Find all the image files in the folder 87 | _projectImageFiles = [FileUtil imageFilesInDirectory:searchPath]; 88 | 89 | NSArray *imageFiles = _projectImageFiles; 90 | if (self.enumFilter) { 91 | NSMutableArray *mutablePngFiles = [NSMutableArray arrayWithArray:imageFiles]; 92 | 93 | // Trying to filter image names like: "Section_0.png", "Section_1.png", etc (these names can possibly be created by [NSString stringWithFormat:@"Section_%d", (int)] constructions) to just "Section_" item 94 | for (NSInteger index = 0, count = [mutablePngFiles count]; index < count; index++) { 95 | NSString *imageName = [mutablePngFiles objectAtIndex:index]; 96 | NSRegularExpression *regExp = [NSRegularExpression regularExpressionWithPattern:@"[_-].*\\d.*.png" options:NSRegularExpressionCaseInsensitive error:nil]; 97 | NSString *newImageName = [regExp stringByReplacingMatchesInString:imageName options:NSMatchingReportProgress range:NSMakeRange(0, [imageName length]) withTemplate:@""]; 98 | if (newImageName) { 99 | [mutablePngFiles replaceObjectAtIndex:index withObject:newImageName]; 100 | } 101 | } 102 | 103 | // Remove duplicates and update pngFiles array 104 | imageFiles = [[NSSet setWithArray:mutablePngFiles] allObjects]; 105 | } 106 | 107 | // Setup all the retina image firstly 108 | // DISCUSSION: performance vs extensibility. Is a n^2 loop better for extensibility or is a large if statement with better effency 109 | for (NSString *pngPath in _projectImageFiles) { 110 | NSString *imageName = [pngPath lastPathComponent]; 111 | 112 | // Does the image have a retina version 113 | for (NSString *retinaRangeString in [self supportedRetinaImagePostfixes]) { 114 | NSRange retinaRange = [imageName rangeOfString:retinaRangeString]; 115 | if (retinaRange.location != NSNotFound) { 116 | // Add to retina image paths 117 | [_retinaImagePaths addObject:pngPath]; 118 | break; 119 | } 120 | } 121 | } 122 | 123 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 124 | dispatch_group_t group = dispatch_group_create(); 125 | 126 | // Now loop and check 127 | [imageFiles enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 128 | dispatch_group_async(group, queue, ^{ 129 | NSString *imagePath = (NSString *)obj; 130 | 131 | BOOL isImagePathEmpty = [imagePath isEqualToString:@""]; 132 | if (!isImagePathEmpty) { 133 | 134 | // Check that it's not a retina image or reserved image name 135 | BOOL isValidImage = [self isValidImageAtPath:imagePath]; 136 | if (isValidImage) { 137 | // Grab the file name 138 | NSString *imageName = [imagePath lastPathComponent]; 139 | 140 | // Settings items 141 | NSArray *settingsItems = [self searchSettings]; 142 | BOOL isSearchCancelled = NO; 143 | for (NSString *extension in settingsItems) { 144 | 145 | // Run the check 146 | if (!isSearchCancelled && [self occurancesOfImageNamed:imageName atDirectory:searchPath inFileExtensionType:extension]) { 147 | isSearchCancelled = YES; 148 | } 149 | } 150 | 151 | // Is it not found - update results 152 | if (!isSearchCancelled) 153 | dispatch_async(dispatch_get_main_queue(), ^{ 154 | 155 | if (self.delegate && [self.delegate respondsToSelector:@selector(searcher:didFindUnusedImage:)]) { 156 | [self.delegate searcher:self didFindUnusedImage:imagePath]; 157 | } 158 | 159 | }); 160 | } 161 | } 162 | }); 163 | }]; 164 | 165 | dispatch_group_notify(group, queue, ^{ 166 | dispatch_async(dispatch_get_main_queue(), ^{ 167 | 168 | [_results sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; 169 | 170 | if (self.delegate && [self.delegate respondsToSelector:@selector(searcher:didFinishSearch:)]) { 171 | [self.delegate searcher:self didFinishSearch:_results]; 172 | } 173 | 174 | isSearching = NO; 175 | [_fileData removeAllObjects]; 176 | }); 177 | }); 178 | } 179 | 180 | - (NSArray *)searchSettings { 181 | 182 | NSMutableArray *settings = [NSMutableArray array]; 183 | 184 | if (self.mSearch) { 185 | [settings addObject:@"m"]; 186 | } 187 | 188 | if (self.xibSearch) { 189 | [settings addObject:@"xib"]; 190 | } 191 | 192 | if (self.storyboardSearch) { 193 | [settings addObject:@"storyboard"]; 194 | } 195 | 196 | if (self.cppSearch) { 197 | [settings addObject:@"cpp"]; 198 | } 199 | 200 | if (self.headerSearch) { 201 | [settings addObject:@"h"]; 202 | } 203 | 204 | if (self.htmlSearch) { 205 | [settings addObject:@"html"]; 206 | } 207 | 208 | if (self.mmSearch) { 209 | [settings addObject:@"mm"]; 210 | } 211 | 212 | if (self.plistSearch) { 213 | [settings addObject:@"plist"]; 214 | } 215 | 216 | if (self.cssSearch) { 217 | [settings addObject:@"css"]; 218 | } 219 | 220 | if (self.swiftSearch) { 221 | [settings addObject:@"swift"]; 222 | } 223 | 224 | return settings; 225 | } 226 | 227 | - (NSArray *)supportedRetinaImagePostfixes { 228 | return @[@"@2x", @"@3x"]; 229 | } 230 | 231 | - (BOOL)isValidImageAtPath:(NSString *)imagePath { 232 | // Grab image name 233 | NSString *imageName = [imagePath lastPathComponent]; 234 | 235 | // Check if is retina 236 | for (NSString *retinaRangeString in [self supportedRetinaImagePostfixes]) { 237 | NSRange retinaRange = [imageName rangeOfString:retinaRangeString]; 238 | if (retinaRange.location != NSNotFound) { 239 | return NO; 240 | } 241 | } 242 | 243 | // Check for reserved names 244 | BOOL isThirdPartyBundle = [imagePath rangeOfString:@".bundle"].length > 0; 245 | BOOL isNamedDefault = [imageName isEqualToString:@"Default.png"]; 246 | BOOL isNamedIcon = [imageName isEqualToString:@"Icon.png"] || [imageName isEqualToString:@"Icon@2x.png"] || [imageName isEqualToString:@"Icon-72.png"]; 247 | BOOL isUniversalImage = [imagePath rangeOfString:@"~ipad" options:NSCaseInsensitiveSearch].length > 0; 248 | 249 | return !(isThirdPartyBundle && isNamedDefault && isNamedIcon && isUniversalImage); 250 | } 251 | 252 | - (int)occurancesOfImageNamed:(NSString *)imageName atDirectory:(NSString *)directoryPath inFileExtensionType:(NSString *)extension { 253 | [_fileDataLock lock]; 254 | 255 | NSData *data = [_fileData objectForKey:directoryPath]; 256 | if (!data) { 257 | NSTask *task = [[NSTask alloc] init]; 258 | [task setLaunchPath: @"/bin/sh"]; 259 | 260 | // Setup the call 261 | NSString *cmd = [NSString stringWithFormat:@"for filename in `find %@ -name '*.%@'`; do cat $filename 2>/dev/null | grep -o %@ ; done", directoryPath, extension, [imageName stringByDeletingPathExtension]]; 262 | NSLog(@"%@", cmd); 263 | NSArray *argvals = [NSArray arrayWithObjects: @"-c", cmd, nil]; 264 | [task setArguments: argvals]; 265 | 266 | NSPipe *pipe = [NSPipe pipe]; 267 | [task setStandardOutput: pipe]; 268 | [task launch]; 269 | 270 | // Read the response 271 | NSFileHandle *file = [pipe fileHandleForReading]; 272 | data = [file readDataToEndOfFile]; 273 | NSString *key = [NSString stringWithFormat:@"%@/%@",directoryPath, imageName]; 274 | 275 | [_fileData setObject:data forKey:key]; 276 | } 277 | 278 | [_fileDataLock unlock]; 279 | 280 | NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 281 | 282 | // Calculate the count 283 | NSScanner *scanner = [NSScanner scannerWithString:string]; 284 | NSCharacterSet *newline = [NSCharacterSet newlineCharacterSet]; 285 | int count = 0; 286 | while ([scanner scanUpToCharactersFromSet:newline intoString:nil]) { 287 | count++; 288 | } 289 | 290 | return count; 291 | } 292 | 293 | @end 294 | -------------------------------------------------------------------------------- /Unused/Unused.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1F168D681AAF1CCD0082E1BC /* CONTRIBUTORS in Resources */ = {isa = PBXBuildFile; fileRef = 1F168D671AAF1CCD0082E1BC /* CONTRIBUTORS */; }; 11 | 1F55B4A81478097A008A4B0E /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F55B4A71478097A008A4B0E /* Cocoa.framework */; }; 12 | 1F55B4B21478097A008A4B0E /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1F55B4B01478097A008A4B0E /* InfoPlist.strings */; }; 13 | 1F55B4B51478097A008A4B0E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F55B4B41478097A008A4B0E /* main.m */; }; 14 | 1F55B4B81478097A008A4B0E /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 1F55B4B61478097A008A4B0E /* Credits.rtf */; }; 15 | 1F55B4BB1478097A008A4B0E /* UnusedAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F55B4BA1478097A008A4B0E /* UnusedAppDelegate.m */; }; 16 | 1F55B4BE1478097A008A4B0E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1F55B4BC1478097A008A4B0E /* MainMenu.xib */; }; 17 | 1F6EFD7A147E597400F8950E /* Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1F6EFD79147E597400F8950E /* Icon.icns */; }; 18 | 1F93632A16D4AC5E00EF0774 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1F93632C16D4AC5E00EF0774 /* Localizable.strings */; }; 19 | 1FBF7B301AA8BBAB00EC2E31 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1FBF7B2F1AA8BBAB00EC2E31 /* Images.xcassets */; }; 20 | 1FBF7B331AA8BD2800EC2E31 /* FileUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FBF7B321AA8BD2800EC2E31 /* FileUtil.m */; }; 21 | 1FBF7B361AAC807500EC2E31 /* Searcher.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FBF7B351AAC807500EC2E31 /* Searcher.m */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | 1F168D671AAF1CCD0082E1BC /* CONTRIBUTORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CONTRIBUTORS; sourceTree = ""; }; 26 | 1F55B4A31478097A008A4B0E /* Unused.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Unused.app; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | 1F55B4A71478097A008A4B0E /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 28 | 1F55B4AA1478097A008A4B0E /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 29 | 1F55B4AB1478097A008A4B0E /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 30 | 1F55B4AC1478097A008A4B0E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 31 | 1F55B4AF1478097A008A4B0E /* Unused-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Unused-Info.plist"; sourceTree = ""; }; 32 | 1F55B4B11478097A008A4B0E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 33 | 1F55B4B31478097A008A4B0E /* Unused-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Unused-Prefix.pch"; sourceTree = ""; }; 34 | 1F55B4B41478097A008A4B0E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | 1F55B4B71478097A008A4B0E /* en */ = {isa = PBXFileReference; lastKnownFileType = wrapper.rtfd; name = en; path = en.lproj/Credits.rtfd; sourceTree = ""; }; 36 | 1F55B4B91478097A008A4B0E /* UnusedAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UnusedAppDelegate.h; sourceTree = ""; }; 37 | 1F55B4BA1478097A008A4B0E /* UnusedAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = UnusedAppDelegate.m; sourceTree = ""; }; 38 | 1F55B4BD1478097A008A4B0E /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 39 | 1F6EFD79147E597400F8950E /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = ""; }; 40 | 1F93632B16D4AC5E00EF0774 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 41 | 1F93632D16D4AC7200EF0774 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; 42 | 1FBF7B2F1AA8BBAB00EC2E31 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 43 | 1FBF7B311AA8BD2800EC2E31 /* FileUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileUtil.h; sourceTree = ""; }; 44 | 1FBF7B321AA8BD2800EC2E31 /* FileUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FileUtil.m; sourceTree = ""; }; 45 | 1FBF7B341AAC807500EC2E31 /* Searcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Searcher.h; sourceTree = ""; }; 46 | 1FBF7B351AAC807500EC2E31 /* Searcher.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Searcher.m; sourceTree = ""; }; 47 | /* End PBXFileReference section */ 48 | 49 | /* Begin PBXFrameworksBuildPhase section */ 50 | 1F55B4A01478097A008A4B0E /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | 1F55B4A81478097A008A4B0E /* Cocoa.framework in Frameworks */, 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXFrameworksBuildPhase section */ 59 | 60 | /* Begin PBXGroup section */ 61 | 1F55B4981478097A008A4B0E = { 62 | isa = PBXGroup; 63 | children = ( 64 | 1F55B4AD1478097A008A4B0E /* Unused */, 65 | 1F55B4A61478097A008A4B0E /* Frameworks */, 66 | 1F55B4A41478097A008A4B0E /* Products */, 67 | ); 68 | sourceTree = ""; 69 | }; 70 | 1F55B4A41478097A008A4B0E /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 1F55B4A31478097A008A4B0E /* Unused.app */, 74 | ); 75 | name = Products; 76 | sourceTree = ""; 77 | }; 78 | 1F55B4A61478097A008A4B0E /* Frameworks */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 1F55B4A71478097A008A4B0E /* Cocoa.framework */, 82 | 1F55B4A91478097A008A4B0E /* Other Frameworks */, 83 | ); 84 | name = Frameworks; 85 | sourceTree = ""; 86 | }; 87 | 1F55B4A91478097A008A4B0E /* Other Frameworks */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 1F55B4AA1478097A008A4B0E /* AppKit.framework */, 91 | 1F55B4AB1478097A008A4B0E /* CoreData.framework */, 92 | 1F55B4AC1478097A008A4B0E /* Foundation.framework */, 93 | ); 94 | name = "Other Frameworks"; 95 | sourceTree = ""; 96 | }; 97 | 1F55B4AD1478097A008A4B0E /* Unused */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 1F55B4B91478097A008A4B0E /* UnusedAppDelegate.h */, 101 | 1F55B4BA1478097A008A4B0E /* UnusedAppDelegate.m */, 102 | 1FBF7B311AA8BD2800EC2E31 /* FileUtil.h */, 103 | 1FBF7B321AA8BD2800EC2E31 /* FileUtil.m */, 104 | 1FBF7B341AAC807500EC2E31 /* Searcher.h */, 105 | 1FBF7B351AAC807500EC2E31 /* Searcher.m */, 106 | 1F55B4BC1478097A008A4B0E /* MainMenu.xib */, 107 | 1FBF7B2F1AA8BBAB00EC2E31 /* Images.xcassets */, 108 | 1F55B4AE1478097A008A4B0E /* Supporting Files */, 109 | ); 110 | path = Unused; 111 | sourceTree = ""; 112 | }; 113 | 1F55B4AE1478097A008A4B0E /* Supporting Files */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 1F93632C16D4AC5E00EF0774 /* Localizable.strings */, 117 | 1F6EFD79147E597400F8950E /* Icon.icns */, 118 | 1F55B4AF1478097A008A4B0E /* Unused-Info.plist */, 119 | 1F55B4B01478097A008A4B0E /* InfoPlist.strings */, 120 | 1F55B4B31478097A008A4B0E /* Unused-Prefix.pch */, 121 | 1F55B4B41478097A008A4B0E /* main.m */, 122 | 1F55B4B61478097A008A4B0E /* Credits.rtf */, 123 | 1F168D671AAF1CCD0082E1BC /* CONTRIBUTORS */, 124 | ); 125 | name = "Supporting Files"; 126 | sourceTree = ""; 127 | }; 128 | /* End PBXGroup section */ 129 | 130 | /* Begin PBXNativeTarget section */ 131 | 1F55B4A21478097A008A4B0E /* Unused */ = { 132 | isa = PBXNativeTarget; 133 | buildConfigurationList = 1F55B4C11478097A008A4B0E /* Build configuration list for PBXNativeTarget "Unused" */; 134 | buildPhases = ( 135 | 1F55B49F1478097A008A4B0E /* Sources */, 136 | 1F55B4A01478097A008A4B0E /* Frameworks */, 137 | 1F55B4A11478097A008A4B0E /* Resources */, 138 | ); 139 | buildRules = ( 140 | ); 141 | dependencies = ( 142 | ); 143 | name = Unused; 144 | productName = Unused; 145 | productReference = 1F55B4A31478097A008A4B0E /* Unused.app */; 146 | productType = "com.apple.product-type.application"; 147 | }; 148 | /* End PBXNativeTarget section */ 149 | 150 | /* Begin PBXProject section */ 151 | 1F55B49A1478097A008A4B0E /* Project object */ = { 152 | isa = PBXProject; 153 | attributes = { 154 | LastUpgradeCheck = 0610; 155 | }; 156 | buildConfigurationList = 1F55B49D1478097A008A4B0E /* Build configuration list for PBXProject "Unused" */; 157 | compatibilityVersion = "Xcode 3.2"; 158 | developmentRegion = English; 159 | hasScannedForEncodings = 0; 160 | knownRegions = ( 161 | en, 162 | fr, 163 | ); 164 | mainGroup = 1F55B4981478097A008A4B0E; 165 | productRefGroup = 1F55B4A41478097A008A4B0E /* Products */; 166 | projectDirPath = ""; 167 | projectRoot = ""; 168 | targets = ( 169 | 1F55B4A21478097A008A4B0E /* Unused */, 170 | ); 171 | }; 172 | /* End PBXProject section */ 173 | 174 | /* Begin PBXResourcesBuildPhase section */ 175 | 1F55B4A11478097A008A4B0E /* Resources */ = { 176 | isa = PBXResourcesBuildPhase; 177 | buildActionMask = 2147483647; 178 | files = ( 179 | 1F168D681AAF1CCD0082E1BC /* CONTRIBUTORS in Resources */, 180 | 1F55B4B21478097A008A4B0E /* InfoPlist.strings in Resources */, 181 | 1F55B4B81478097A008A4B0E /* Credits.rtf in Resources */, 182 | 1F55B4BE1478097A008A4B0E /* MainMenu.xib in Resources */, 183 | 1FBF7B301AA8BBAB00EC2E31 /* Images.xcassets in Resources */, 184 | 1F6EFD7A147E597400F8950E /* Icon.icns in Resources */, 185 | 1F93632A16D4AC5E00EF0774 /* Localizable.strings in Resources */, 186 | ); 187 | runOnlyForDeploymentPostprocessing = 0; 188 | }; 189 | /* End PBXResourcesBuildPhase section */ 190 | 191 | /* Begin PBXSourcesBuildPhase section */ 192 | 1F55B49F1478097A008A4B0E /* Sources */ = { 193 | isa = PBXSourcesBuildPhase; 194 | buildActionMask = 2147483647; 195 | files = ( 196 | 1FBF7B331AA8BD2800EC2E31 /* FileUtil.m in Sources */, 197 | 1F55B4B51478097A008A4B0E /* main.m in Sources */, 198 | 1FBF7B361AAC807500EC2E31 /* Searcher.m in Sources */, 199 | 1F55B4BB1478097A008A4B0E /* UnusedAppDelegate.m in Sources */, 200 | ); 201 | runOnlyForDeploymentPostprocessing = 0; 202 | }; 203 | /* End PBXSourcesBuildPhase section */ 204 | 205 | /* Begin PBXVariantGroup section */ 206 | 1F55B4B01478097A008A4B0E /* InfoPlist.strings */ = { 207 | isa = PBXVariantGroup; 208 | children = ( 209 | 1F55B4B11478097A008A4B0E /* en */, 210 | ); 211 | name = InfoPlist.strings; 212 | sourceTree = ""; 213 | }; 214 | 1F55B4B61478097A008A4B0E /* Credits.rtf */ = { 215 | isa = PBXVariantGroup; 216 | children = ( 217 | 1F55B4B71478097A008A4B0E /* en */, 218 | ); 219 | name = Credits.rtf; 220 | sourceTree = ""; 221 | }; 222 | 1F55B4BC1478097A008A4B0E /* MainMenu.xib */ = { 223 | isa = PBXVariantGroup; 224 | children = ( 225 | 1F55B4BD1478097A008A4B0E /* en */, 226 | ); 227 | name = MainMenu.xib; 228 | sourceTree = ""; 229 | }; 230 | 1F93632C16D4AC5E00EF0774 /* Localizable.strings */ = { 231 | isa = PBXVariantGroup; 232 | children = ( 233 | 1F93632B16D4AC5E00EF0774 /* en */, 234 | 1F93632D16D4AC7200EF0774 /* fr */, 235 | ); 236 | name = Localizable.strings; 237 | sourceTree = ""; 238 | }; 239 | /* End PBXVariantGroup section */ 240 | 241 | /* Begin XCBuildConfiguration section */ 242 | 1F55B4BF1478097A008A4B0E /* Debug */ = { 243 | isa = XCBuildConfiguration; 244 | buildSettings = { 245 | CLANG_WARN_BOOL_CONVERSION = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_EMPTY_BODY = YES; 248 | CLANG_WARN_ENUM_CONVERSION = YES; 249 | CLANG_WARN_INT_CONVERSION = YES; 250 | CLANG_WARN_UNREACHABLE_CODE = YES; 251 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 252 | ENABLE_STRICT_OBJC_MSGSEND = YES; 253 | GCC_C_LANGUAGE_STANDARD = gnu99; 254 | GCC_OPTIMIZATION_LEVEL = 0; 255 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG; 256 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 257 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 258 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 259 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 260 | GCC_WARN_UNDECLARED_SELECTOR = YES; 261 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 262 | GCC_WARN_UNUSED_FUNCTION = YES; 263 | GCC_WARN_UNUSED_VARIABLE = YES; 264 | MACOSX_DEPLOYMENT_TARGET = 10.6; 265 | ONLY_ACTIVE_ARCH = YES; 266 | SDKROOT = macosx; 267 | }; 268 | name = Debug; 269 | }; 270 | 1F55B4C01478097A008A4B0E /* Release */ = { 271 | isa = XCBuildConfiguration; 272 | buildSettings = { 273 | CLANG_WARN_BOOL_CONVERSION = YES; 274 | CLANG_WARN_CONSTANT_CONVERSION = YES; 275 | CLANG_WARN_EMPTY_BODY = YES; 276 | CLANG_WARN_ENUM_CONVERSION = YES; 277 | CLANG_WARN_INT_CONVERSION = YES; 278 | CLANG_WARN_UNREACHABLE_CODE = YES; 279 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 280 | ENABLE_STRICT_OBJC_MSGSEND = YES; 281 | GCC_C_LANGUAGE_STANDARD = gnu99; 282 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 283 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 284 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 285 | GCC_WARN_UNDECLARED_SELECTOR = YES; 286 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 287 | GCC_WARN_UNUSED_FUNCTION = YES; 288 | GCC_WARN_UNUSED_VARIABLE = YES; 289 | MACOSX_DEPLOYMENT_TARGET = 10.6; 290 | SDKROOT = macosx; 291 | }; 292 | name = Release; 293 | }; 294 | 1F55B4C21478097A008A4B0E /* Debug */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ALWAYS_SEARCH_USER_PATHS = NO; 298 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 299 | CLANG_ENABLE_OBJC_ARC = YES; 300 | CODE_SIGN_IDENTITY = ""; 301 | COMBINE_HIDPI_IMAGES = YES; 302 | COPY_PHASE_STRIP = NO; 303 | GCC_DYNAMIC_NO_PIC = NO; 304 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 305 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 306 | GCC_PREFIX_HEADER = "Unused/Unused-Prefix.pch"; 307 | INFOPLIST_FILE = "Unused/Unused-Info.plist"; 308 | PRODUCT_NAME = "$(TARGET_NAME)"; 309 | WRAPPER_EXTENSION = app; 310 | }; 311 | name = Debug; 312 | }; 313 | 1F55B4C31478097A008A4B0E /* Release */ = { 314 | isa = XCBuildConfiguration; 315 | buildSettings = { 316 | ALWAYS_SEARCH_USER_PATHS = NO; 317 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 318 | CLANG_ENABLE_OBJC_ARC = YES; 319 | CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application: Seamonster Ltd."; 320 | COMBINE_HIDPI_IMAGES = YES; 321 | COPY_PHASE_STRIP = YES; 322 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 323 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 324 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 325 | GCC_PREFIX_HEADER = "Unused/Unused-Prefix.pch"; 326 | INFOPLIST_FILE = "Unused/Unused-Info.plist"; 327 | PRODUCT_NAME = "$(TARGET_NAME)"; 328 | WRAPPER_EXTENSION = app; 329 | }; 330 | name = Release; 331 | }; 332 | 1F9DF8EF1487E47A00A1EAC8 /* Distribution */ = { 333 | isa = XCBuildConfiguration; 334 | buildSettings = { 335 | CLANG_WARN_BOOL_CONVERSION = YES; 336 | CLANG_WARN_CONSTANT_CONVERSION = YES; 337 | CLANG_WARN_EMPTY_BODY = YES; 338 | CLANG_WARN_ENUM_CONVERSION = YES; 339 | CLANG_WARN_INT_CONVERSION = YES; 340 | CLANG_WARN_UNREACHABLE_CODE = YES; 341 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 342 | ENABLE_STRICT_OBJC_MSGSEND = YES; 343 | GCC_C_LANGUAGE_STANDARD = gnu99; 344 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 345 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 346 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 347 | GCC_WARN_UNDECLARED_SELECTOR = YES; 348 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 349 | GCC_WARN_UNUSED_FUNCTION = YES; 350 | GCC_WARN_UNUSED_VARIABLE = YES; 351 | MACOSX_DEPLOYMENT_TARGET = 10.6; 352 | SDKROOT = macosx; 353 | }; 354 | name = Distribution; 355 | }; 356 | 1F9DF8F01487E47A00A1EAC8 /* Distribution */ = { 357 | isa = XCBuildConfiguration; 358 | buildSettings = { 359 | ALWAYS_SEARCH_USER_PATHS = NO; 360 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 361 | CLANG_ENABLE_OBJC_ARC = YES; 362 | CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application: Seamonster Ltd."; 363 | COMBINE_HIDPI_IMAGES = YES; 364 | COPY_PHASE_STRIP = YES; 365 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 366 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 367 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 368 | GCC_PREFIX_HEADER = "Unused/Unused-Prefix.pch"; 369 | INFOPLIST_FILE = "Unused/Unused-Info.plist"; 370 | PRODUCT_NAME = "$(TARGET_NAME)"; 371 | PROVISIONING_PROFILE = "7B15303B-2950-41B3-8360-420802231324"; 372 | WRAPPER_EXTENSION = app; 373 | }; 374 | name = Distribution; 375 | }; 376 | /* End XCBuildConfiguration section */ 377 | 378 | /* Begin XCConfigurationList section */ 379 | 1F55B49D1478097A008A4B0E /* Build configuration list for PBXProject "Unused" */ = { 380 | isa = XCConfigurationList; 381 | buildConfigurations = ( 382 | 1F55B4BF1478097A008A4B0E /* Debug */, 383 | 1F55B4C01478097A008A4B0E /* Release */, 384 | 1F9DF8EF1487E47A00A1EAC8 /* Distribution */, 385 | ); 386 | defaultConfigurationIsVisible = 0; 387 | defaultConfigurationName = Release; 388 | }; 389 | 1F55B4C11478097A008A4B0E /* Build configuration list for PBXNativeTarget "Unused" */ = { 390 | isa = XCConfigurationList; 391 | buildConfigurations = ( 392 | 1F55B4C21478097A008A4B0E /* Debug */, 393 | 1F55B4C31478097A008A4B0E /* Release */, 394 | 1F9DF8F01487E47A00A1EAC8 /* Distribution */, 395 | ); 396 | defaultConfigurationIsVisible = 0; 397 | defaultConfigurationName = Release; 398 | }; 399 | /* End XCConfigurationList section */ 400 | }; 401 | rootObject = 1F55B49A1478097A008A4B0E /* Project object */; 402 | } 403 | -------------------------------------------------------------------------------- /Unused/Unused/en.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | Default 523 | 524 | 525 | 526 | 527 | 528 | 529 | Left to Right 530 | 531 | 532 | 533 | 534 | 535 | 536 | Right to Left 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | Default 548 | 549 | 550 | 551 | 552 | 553 | 554 | Left to Right 555 | 556 | 557 | 558 | 559 | 560 | 561 | Right to Left 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 726 | 727 | 728 | 729 | 730 | 731 | 739 | 747 | 755 | 763 | 771 | 779 | 787 | 795 | 803 | 814 | 825 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | --------------------------------------------------------------------------------