What are some good Xcode scripts to speed up development?

前端 未结 6 507
情深已故
情深已故 2021-01-31 12:54

Xcode allows you to create automated scripts for performing repetitive tasks. What scripts have you written to speed up development?

相关标签:
6条回答
  • 2021-01-31 12:59

    Here's one that I found somewhere else that creates @property (copy) and @synthesize property directives for an instance variable. It could use a bit of improvement (say, to let you synthesize multiple variables at once), but it's better than creating them by hand.

    Select the instance variable you want to create a property for and activate the script.

    If I want a (retain) instead of (copy) I just activate the script and change it to retain manually (it's smart enough to not include the (copy) on primitive types such as int to begin with).

    #! /usr/bin/perl -w
    
    #Create property from instance variable
    
    #Entire Document
    #Home Directory
    #Discard Output
    #Display in Alert
    
    use strict;
    
    # Get the header file contents from Xcode user scripts
    my $headerFileContents = <<'HEADERFILECONTENTS';
    %%%{PBXAllText}%%%
    HEADERFILECONTENTS
    
    # Get the indices of the selection from Xcode user scripts
    my $selectionStartIndex = %%%{PBXSelectionStart}%%%;
    my $selectionEndIndex = %%%{PBXSelectionEnd}%%%;
    
    # Get path of the header file
    my $implementationFilePath = "%%%{PBXFilePath}%%%";
    my $headerFilePath = $implementationFilePath;
    
    # Look for an implemenation file with a ".m" or ".mm" extension
    $implementationFilePath =~ s/\.[hm]*$/.m/;
    if (!(-e $implementationFilePath))
    {
        $implementationFilePath =~ s/.m$/.mm/;
    }
    
    # Handle subroutine to trime whitespace off both ends of a string
    sub trim
    {
        my $string = shift;
        $string =~ s/^\s*(.*?)\s*$/$1/;
        return $string;
    }
    
    # Get the selection out of the header file
    my $selectedText =  substr $headerFileContents, $selectionStartIndex, ($selectionEndIndex - $selectionStartIndex);
    $selectedText = trim $selectedText;
    
    my $type = "";
    my $asterisk = "";
    my $name = "";
    my $behavior = "";
    
    # Test that the selection is:
    #  At series of identifiers (the type name and access specifiers)
    #  Possibly an asterisk
    #  Another identifier (the variable name)
    #  A semi-colon
    if (length($selectedText) && ($selectedText =~ /([_A-Za-z][_A-Za-z0-9]*\s*)+([\s\*]+)([_A-Za-z][_A-Za-z0-9]*);/))
    {
        $type = $1;
        $type = trim $type;
        $asterisk = $2;
        $asterisk = trim $asterisk;
        $name = $3;
        $behavior = "";
        if (defined($asterisk) && length($asterisk) == 1)
        {
            $behavior = "(copy) "; #"(nonatomic, retain) ";
        }
        else
        {
            $asterisk = "";
        }
    }
    else
    {
        exit 1;
    }
    
    # Find the closing brace (end of the class variables section)
    my $remainderOfHeader = substr $headerFileContents, $selectionEndIndex;
    my $indexAfterClosingBrace = $selectionEndIndex + index($remainderOfHeader, "\n}\n") + 3;
    if ($indexAfterClosingBrace == -1)
    {
        exit 1;
    }
    
    # Determine if we need to add a newline in front of the property declaration
    my $leadingNewline = "\n";
    if (substr($headerFileContents, $indexAfterClosingBrace, 1) eq "\n")
    {
        $indexAfterClosingBrace += 1;
        $leadingNewline = "";
    }
    
    # Determine if we need to add a newline after the property declaration
    my $trailingNewline = "\n";
    if (substr($headerFileContents, $indexAfterClosingBrace, 9) eq "\@property")
    {
        $trailingNewline = "";
    }
    
    # Create and insert the propert declaration
    my $propertyDeclaration = $leadingNewline . "\@property " . $behavior . $type . " " . $asterisk . $name . ";\n" . $trailingNewline;
    substr($headerFileContents, $indexAfterClosingBrace, 0) = $propertyDeclaration;
    
    my $replaceFileContentsScript = <<'REPLACEFILESCRIPT';
    on run argv
        set fileAlias to POSIX file (item 1 of argv)
        set newDocText to (item 2 of argv)
        tell application "Xcode"
            set doc to open fileAlias
            set text of doc to newDocText
        end tell
    end run
    REPLACEFILESCRIPT
    
    # Use Applescript to replace the contents of the header file
    # (I could have used the "Output" of the Xcode user script instead)
    system 'osascript', '-e', $replaceFileContentsScript, $headerFilePath, $headerFileContents;
    
    # Stop now if the implementation file can't be found
    if (!(-e $implementationFilePath))
    {
        exit 1;
    }
    
    my $getFileContentsScript = <<'GETFILESCRIPT';
    on run argv
        set fileAlias to POSIX file (item 1 of argv)
        tell application "Xcode"
            set doc to open fileAlias
            set docText to text of doc
        end tell
        return docText
    end run
    GETFILESCRIPT
    
    # Get the contents of the implmentation file
    open(SCRIPTFILE, '-|') || exec 'osascript', '-e', $getFileContentsScript, $implementationFilePath;
    my $implementationFileContents = do {local $/; <SCRIPTFILE>};
    close(SCRIPTFILE);
    
    # Look for the class implementation statement
    if (length($implementationFileContents) && ($implementationFileContents =~ /(\@implementation [_A-Za-z][_A-Za-z0-9]*\n)/))
    {
        my $matchString = $1;
        my $indexAfterMatch = index($implementationFileContents, $matchString) + length($matchString);
    
        # Determine if we want a newline before the synthesize statement
        $leadingNewline = "\n";
        if (substr($implementationFileContents, $indexAfterMatch, 1) eq "\n")
        {
            $indexAfterMatch += 1;
            $leadingNewline = "";
        }
    
        # Determine if we want a newline after the synthesize statement
        $trailingNewline = "\n";
        if (substr($implementationFileContents, $indexAfterMatch, 11) eq "\@synthesize")
        {
            $trailingNewline = "";
        }
    
        # Create and insert the synthesize statement 
        my $synthesizeStatement = $leadingNewline . "\@synthesize " . $name . ";\n" . $trailingNewline;
        substr($implementationFileContents, $indexAfterMatch, 0) = $synthesizeStatement;
    
        # Use Applescript to replace the contents of the implementation file in Xcode
        system 'osascript', '-e', $replaceFileContentsScript, $implementationFilePath, $implementationFileContents;
    }
    
    exit 0;
    
    0 讨论(0)
  • 2021-01-31 13:01

    I've created three for my JSON.Framework for Cocoa and the iPhone. These take care of the following:

    • Creates a release Disk Image with dynamic embedded Framework, custom iPhone SDK, API documentation and some documentation files in.
    • Run Doxygen over the source to create an Xcode-compatible documentation set and install this. This means when you search for things in Xcode's documentation search your documentation can be found too.
    • Run Doxygen over the source to update a checked-in version of the API documentation in the source tree itself. This is pretty neat if you use Subversion (which it assumes) as the documentation is always up-to-date for the branch you're in. Great if you're hosting on Google Code, for example.

    Beware some hard-coded project-specific values in the below. I didn't want to potentially break the scripts by editing those out. These are launched from a Custom Script Phase in Xcode. You can see how they're integrated in the Xcode project for the project linked above.

    CreateDiskImage.sh:

    #!/bin/sh
    
    set -x
    
    # Determine the project name and version
    VERS=$(agvtool mvers -terse1)
    
    # Derived names
    VOLNAME=${PROJECT}_${VERS}
    DISK_IMAGE=$BUILD_DIR/$VOLNAME
    DISK_IMAGE_FILE=$INSTALL_DIR/$VOLNAME.dmg
    
    # Remove old targets
    rm -f $DISK_IMAGE_FILE
    test -d $DISK_IMAGE && chmod -R +w $DISK_IMAGE && rm -rf $DISK_IMAGE
    mkdir -p $DISK_IMAGE
    
    # Create the Embedded framework and copy it to the disk image.
    xcodebuild -target JSON -configuration Release install || exit 1
    cp -p -R $INSTALL_DIR/../Frameworks/$PROJECT.framework $DISK_IMAGE
    
    IPHONE_SDK=2.2.1
    
    # Create the iPhone SDK directly in the disk image folder.
    xcodebuild -target libjson -configuration Release -sdk iphoneos$IPHONE_SDK install \
        ARCHS=armv6 \
        DSTROOT=$DISK_IMAGE/SDKs/JSON/iphoneos.sdk || exit 1
    sed -e "s/%PROJECT%/$PROJECT/g" \
        -e "s/%VERS%/$VERS/g" \
        -e "s/%IPHONE_SDK%/$IPHONE_SDK/g" \
        $SOURCE_ROOT/Resources/iphoneos.sdk/SDKSettings.plist > $DISK_IMAGE/SDKs/JSON/iphoneos.sdk/SDKSettings.plist || exit 1
    
    xcodebuild -target libjson -configuration Release -sdk iphonesimulator$IPHONE_SDK install \
        ARCHS=i386 \
        DSTROOT=$DISK_IMAGE/SDKs/JSON/iphonesimulator.sdk || exit 1
    sed -e "s/%PROJECT%/$PROJECT/g" \
        -e "s/%VERS%/$VERS/g" \
        -e "s/%IPHONE_SDK%/$IPHONE_SDK/g" \
        $SOURCE_ROOT/Resources/iphonesimulator.sdk/SDKSettings.plist > $DISK_IMAGE/SDKs/JSON/iphonesimulator.sdk/SDKSettings.plist || exit 1    
    
    # Allow linking statically into normal OS X apps
    xcodebuild -target libjson -configuration Release -sdk macosx10.5 install \
        DSTROOT=$DISK_IMAGE/SDKs/JSON/macosx.sdk || exit 1
    
    # Copy the source verbatim into the disk image.
    cp -p -R $SOURCE_ROOT/Source $DISK_IMAGE/$PROJECT
    rm -rf $DISK_IMAGE/$PROJECT/.svn
    
    # Create the documentation
    xcodebuild -target Documentation -configuration Release install || exit 1
    cp -p -R $INSTALL_DIR/Documentation/html $DISK_IMAGE/Documentation
    rm -rf $DISK_IMAGE/Documentation/.svn
    
    cat <<HTML > $DISK_IMAGE/Documentation.html
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <script type="text/javascript">
    <!--
    window.location = "Documentation/index.html"
    //-->
    </script>
    </head>
    <body>
    <p>Aw, shucks! I tried to redirect you to the <a href="Documentaton/index.html">api documentation</a> but obviously failed. Please find it yourself. </p>
    </body>
    </html>
    HTML
    
    cp -p $SOURCE_ROOT/README $DISK_IMAGE
    cp -p $SOURCE_ROOT/Credits.rtf $DISK_IMAGE
    cp -p $SOURCE_ROOT/Install.rtf $DISK_IMAGE
    cp -p $SOURCE_ROOT/Changes.rtf $DISK_IMAGE
    
    hdiutil create -fs HFS+ -volname $VOLNAME -srcfolder $DISK_IMAGE $DISK_IMAGE_FILE
    

    InstallDocumentation.sh:

    #!/bin/sh
    # See also http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 
    
    set -x
    
    VERSION=$(agvtool mvers -terse1)
    
    DOXYFILE=$DERIVED_FILES_DIR/doxygen.config
    DOXYGEN=/Applications/Doxygen.app/Contents/Resources/doxygen
    DOCSET=$INSTALL_DIR/Docset
    
    rm -rf $DOCSET
    mkdir -p $DOCSET || exit 1
    mkdir -p $DERIVED_FILES_DIR || exit 1
    
    if ! test -x $DOXYGEN ; then
        echo "*** Install Doxygen to get documentation generated for you automatically ***"
        exit 1
    fi
    
    # Create a doxygen configuration file with only the settings we care about
    $DOXYGEN -g - > $DOXYFILE
    
    cat <<EOF >> $DOXYFILE
    
    PROJECT_NAME           = $FULL_PRODUCT_NAME
    PROJECT_NUMBER         = $VERSION
    OUTPUT_DIRECTORY       = $DOCSET
    INPUT                  = $SOURCE_ROOT/Source
    FILE_PATTERNS          = *.h *.m
    
    HIDE_UNDOC_MEMBERS     = YES
    HIDE_UNDOC_CLASSES     = YES
    HIDE_UNDOC_RELATIONS   = YES
    REPEAT_BRIEF           = NO
    CASE_SENSE_NAMES       = YES
    INLINE_INHERITED_MEMB  = YES
    SHOW_FILES             = NO
    SHOW_INCLUDE_FILES     = NO
    GENERATE_LATEX         = NO
    GENERATE_HTML          = YES
    GENERATE_DOCSET        = YES
    DOCSET_FEEDNAME        = "$PROJECT.framework API Documentation"
    DOCSET_BUNDLE_ID       = org.brautaset.$PROJECT
    
    EOF
    
    #  Run doxygen on the updated config file.
    #  doxygen creates a Makefile that does most of the heavy lifting.
    $DOXYGEN $DOXYFILE
    
    #  make will invoke docsetutil. Take a look at the Makefile to see how this is done.
    make -C $DOCSET/html install
    
    #  Construct a temporary applescript file to tell Xcode to load a docset.
    rm -f $TEMP_DIR/loadDocSet.scpt
    
    cat <<EOF > $TEMP_DIR/loadDocSet.scpt
    tell application "Xcode"
        load documentation set with path "/Users/$USER/Library/Developer/Shared/Documentation/DocSets/org.brautaset.${PROJECT}.docset/"
    end tell
    EOF
    
    # Run the load-docset applescript command.
    osascript $TEMP_DIR/loadDocSet.scpt
    

    RegenerateDocumentation.sh:

    #!/bin/sh
    # See also http://developer.apple.com/tools/creatingdocsetswithdoxygen.html 
    
    set -x
    
    VERSION=$(agvtool mvers -terse1)
    
    DOXYFILE=$DERIVED_FILES_DIR/doxygen.config
    DOXYGEN=/Applications/Doxygen.app/Contents/Resources/doxygen
    DOCSET=$INSTALL_DIR/Documentation
    APIDOCDIR=$SOURCE_ROOT/documentation
    
    rm -rf $DOCSET
    mkdir -p $DOCSET || exit 1
    mkdir -p $DERIVED_FILES_DIR || exit 1
    
    if ! test -x $DOXYGEN ; then
        echo "*** Install Doxygen to get documentation generated for you automatically ***"
        exit 1
    fi
    
    # Create a doxygen configuration file with only the settings we care about
    $DOXYGEN -g - > $DOXYFILE
    
    cat <<EOF >> $DOXYFILE
    
    PROJECT_NAME           = $FULL_PRODUCT_NAME
    PROJECT_NUMBER         = $VERSION
    OUTPUT_DIRECTORY       = $DOCSET
    INPUT                  = $SOURCE_ROOT/Source
    FILE_PATTERNS          = *.h *.m
    
    HIDE_UNDOC_MEMBERS     = YES
    HIDE_UNDOC_CLASSES     = YES
    HIDE_UNDOC_RELATIONS   = YES
    REPEAT_BRIEF           = NO
    CASE_SENSE_NAMES       = YES
    INLINE_INHERITED_MEMB  = YES
    SHOW_FILES             = NO
    SHOW_INCLUDE_FILES     = NO
    GENERATE_LATEX         = NO
    GENERATE_HTML          = YES
    GENERATE_DOCSET        = NO
    
    EOF
    
    #  Run doxygen on the updated config file.
    $DOXYGEN $DOXYFILE
    
    # Replace the old dir with the newly generated one.
    rm -f $APIDOCDIR/*
    cp -p $DOCSET/html/* $APIDOCDIR
    cd $APIDOCDIR
    
    # Revert files that differ only in the timestamp.
    svn diff *.html | diffstat | awk '$3 == 2 { print $1 }' | xargs svn revert
    
    # Add/remove files from subversion.
    svn st | awk '
        $1 == "?" { print "svn add", $2 }
        $1 == "!" { print "svn delete",  $2 }
    ' | sh -
    
    svn propset svn:mime-type text/html *.html
    svn propset svn:mime-type text/css *.css
    svn propset svn:mime-type image/png *.png
    svn propset svn:mime-type image/gif *.gif
    
    0 讨论(0)
  • 2021-01-31 13:01

    Here's one to log a method and its arguments any time it's executed (Select the method definition up through the lie with the opening brace and execute the script). If FIXME shows up in the output it means it's an unrecognized type. You can either add it to the script or choose the proper format specifier manually.

    #!/usr/bin/python
    
    # LogMethod
    # Selection
    # Selection
    # Insert after Selection
    # Display in Alert
    
    import sys
    import re
    
    input = sys.stdin.read()
    
    methodPieces = re.findall("""(\w*:)""", input)
    vars = re.findall(""":\(([^)]*)\)[ ]?(\w*)""", input)
    
    outputStrings = ["\n  NSLog(@\""]
    
    # Method taking no parameters
    if not methodPieces:
        outputStrings.append(re.findall("""(\w*)[ ]?{""", input)[0])
    
    for (methodPiece, var) in zip(methodPieces, vars):
        type = var[0]
        outputStrings.append(methodPiece)
        if "**" in type:
            outputStrings.append("%p")
        elif "*" in type:
            if "char" in type:
                outputStrings.append("%c")
            else:
                outputStrings.append("%@")
        else:
            if "int" in type or "NSInteger" in type or "BOOL" in type:
                outputStrings.append("%i")
            elif "NSUInteger" in type:
                outputStrings.append("%u")
            elif "id" in type:
                outputStrings.append("%@")
            elif "NSTimeInterval" in type:
                outputStrings.append("%f")
            elif "SEL" in type:
                outputString.append("%s")
            else:
                outputStrings.append('"FIXME"')
        if not methodPiece == methodPieces[-1]:
            outputStrings.append('\\n"\n         @"')
    
    outputStrings.append("\"")
    
    for var in vars:
        name = var[1]
        outputStrings.append(",\n         ")
        outputStrings.append(name)
    
    outputStrings.append(");")
    
    print "".join(outputStrings),
    
    0 讨论(0)
  • 2021-01-31 13:10

    This on creates @proptery, @synthesize, dealloc, viewDidUnload and public methods for you. Easy XCode integration:

    http://github.com/holtwick/xobjc

    0 讨论(0)
  • 2021-01-31 13:15

    Here's one to create a -description method for a class. Highlight the instance variables declaration section (@interface ... { ... }) and execute the script. Then paste the result into your implementation. I use this one along with po objectName in GDB. If FIXME shows up in the output it means it's an unrecognized type. You can either add it to the script or choose the proper format specifier manually.

    #!/usr/bin/python
    
    # Create description method for class
    # Selection
    # Selection
    # Insert after Selection
    # Display in Alert
    
    import sys
    import re
    
    input = sys.stdin.read()
    
    className = re.findall("""(?:@interface )(\w*)""", input)[0]
    vars = re.findall("""(\w*[ ][*]?)(\w*?)_?;""", input)
    
    outputStrings = ["- (NSString *)description {\n"]
    outputStrings.append("""return [NSString stringWithFormat:@"%s :\\n"\n@"  -""" % className)
    
    for type, var in vars:
        outputStrings.append("%s:" % var)
        if "**" in type:
            outputStrings.append("%p")
        elif "*" in type:
            if "char" in type:
                outputStrings.append("%c")
            else:
                outputStrings.append("%@")
        else:
            if "int" in type or "NSInteger" in type or "BOOL" in type:
                outputStrings.append("%i")
            elif "NSUInteger" in type:
                outputStrings.append("%u")
            elif "id" in type:
                outputStrings.append("%@")
            elif "NSTimeInterval" in type:
                outputStrings.append("%f")
            elif "SEL" in type:
                outputString.append("%s")
            else:
                outputStrings.append('"FIXME"')
    
        if not var == vars[-1][1]:
            outputStrings.append(',\\n"\n@"  -')
    
    outputStrings.append("\"")
    
    for type, var in vars:
        outputStrings.append(",\n")
        outputStrings.append("[self %s]" % var)
    
    outputStrings.append("];\n}")
    
    print "".join(outputStrings),
    
    0 讨论(0)
  • 2021-01-31 13:26

    This is an improvement of the "Create Property and Synths for instance variables" script that Lawrence Johnston posted above.

    Settings:

    Input: Entire Document Directory: Home Directory Output: Discard Output Errors: Ignore Errors (or Alert if you want to see them)

    Select any number of variables and it'll create properties and syns for all of them. It'll even create/edit your dalloc method as necessary.

    Edit up the results if they are not exactly right (copy vs. retain, etc.)

    Handles more things like underbar storage name, behavior, dealloc,…

    Link to where this comes from and discussion: http://cocoawithlove.com/2008/12/instance-variable-to-synthesized.html

    #! /usr/bin/perl -w
    
    #  Created by Matt Gallagher on 20/10/08.
    #  Copyright 2008 Matt Gallagher. All rights reserved.
    #
    #  Enhancements by Yung-Luen Lan and Mike Schrag on 12/08/09.
    #  (mainly: multiple lines)
    #  Copyright 2009 Yung-Luen Lan and Mike Schrag. All rights reserved.
    #
    #  Enhancements by Pierre Bernard on 20/09/09.
    #  (mainly: underbar storage name, behavior, dealloc,…)
    #  Copyright 2009 Pierre Bernard. All rights reserved.
    #
    #  Permission is given to use this source code file without charge in any
    #  project, commercial or otherwise, entirely at your risk, with the condition
    #  that any redistribution (in part or whole) of source code must retain
    #  this copyright and permission notice. Attribution in compiled projects is
    #  appreciated but not required.
    
    use strict;
    
    # Get the header file contents from Xcode user scripts
    my $headerFileContents = <<'HEADERFILECONTENTS';
    %%%{PBXAllText}%%%
    HEADERFILECONTENTS
    
    # Get the indices of the selection from Xcode user scripts
    my $selectionStartIndex = %%%{PBXSelectionStart}%%%;
    my $selectionEndIndex = %%%{PBXSelectionEnd}%%%;
    
    
    
    # Find the closing brace (end of the class variables section)
    my $remainderOfHeader = substr $headerFileContents, $selectionEndIndex;
    my $indexAfterClosingBrace = $selectionEndIndex + index($remainderOfHeader, "\n}\n") + 3;
    if ($indexAfterClosingBrace == -1)
    {
     exit 1;
    }
    
    
    # Get path of the header file
    my $implementationFilePath = "%%%{PBXFilePath}%%%";
    my $headerFilePath = $implementationFilePath;
    
    # Look for an implemenation file with a ".m" or ".mm" extension
    $implementationFilePath =~ s/\.[hm]*$/.m/;
    if (!(-e $implementationFilePath))
    {
     $implementationFilePath =~ s/.m$/.mm/;
    }
    
    # Stop now if the implementation file can't be found
    if (!(-e $implementationFilePath))
    {
     exit 1;
    }
    
    
    my $propertyDeclarations = '';
    my $synthesizeStatements = '';
    my $releaseStatements = '';
    
    
    
    # Handle subroutine to trim whitespace off both ends of a string
    sub trim
    {
     my $string = shift;
     $string =~ s/^\s*(.*?)\s*$/$1/;
     return $string;
    }
    
    # Get the selection out of the header file
    my $selectedText =  substr $headerFileContents, $selectionStartIndex, ($selectionEndIndex - $selectionStartIndex);
    $selectedText = trim $selectedText;
    
    my $selectedLine;
    
    foreach $selectedLine (split(/\n+/, $selectedText)) {
     my $type = '';
     my $asterisk = '';
     my $name = '';
     my $behavior = '';
    
     # Test that the selection is:
     #  At series of identifiers (the type name and access specifiers)
     #  Possibly an asterisk
     #  Another identifier (the variable name)
     #  A semi-colon
     if (length($selectedLine) && ($selectedLine =~ /([_A-Za-z][_A-Za-z0-9]*\s*)+([\s\*]+)([_A-Za-z][_A-Za-z0-9]*);/))
     {
      $type = $1;
      $type = trim $type;
      $asterisk = $2;
      $asterisk = trim $asterisk;
      $name = $3;
      $behavior = 'assign';
    
      if (defined($asterisk) && length($asterisk) == 1)
      {
       if (($type eq 'NSString') || ($type eq 'NSArray') || ($type eq 'NSDictionary') || ($type eq 'NSSet'))
       {
        $behavior = 'copy';
       }
       else
       {
        if (($name =~ /Delegate/) || ($name =~ /delegate/) || ($type =~ /Delegate/) || ($type =~ /delegate/))
        {
         $behavior = 'assign';
        }
        else
        {
         $behavior = 'retain';
        }
       }
      }
      else
      {
       if ($type eq 'id')
       {
        $behavior = 'copy';
       }
    
       $asterisk = '';
      }
     }
     else
     {
      next;
     }
    
     my $storageName = '';
    
     if ($name =~ /_([_A-Za-z][_A-Za-z0-9]*)/) {
      $storageName = $name;
      $name = $1;  
     }
    
    
     # Create and insert the propert declaration
     my $propertyDeclaration = "\@property (nonatomic, $behavior) $type " . $asterisk . $name . ";\n";
    
     $propertyDeclarations = $propertyDeclarations . $propertyDeclaration;
    
    
    
     # Create and insert the synthesize statement 
     my $synthesizeStatement = '';
    
     if (length($storageName))
     {
      $synthesizeStatement = "\@synthesize $name = $storageName;\n";
     }
     else
     {
      $synthesizeStatement =  "\@synthesize $name;\n";
     }
    
     $synthesizeStatements = $synthesizeStatements . $synthesizeStatement;
    
    
    
     # Create and insert release statement  
     my $releaseName = $name;
     my $releaseStatement = '';  
    
     if (length($storageName))
     {
      $releaseName = $storageName;  
     }
    
     if ($behavior eq 'assign')
     {
      if ($type eq 'SEL')
      {
       $releaseStatement = "\t$releaseName = NULL;\n";  
      }
     }
     else 
     {
      $releaseStatement = "\t[$releaseName release];\n\t$releaseName = nil;\n";  
     }
    
     $releaseStatements = $releaseStatements . $releaseStatement;
    }
    
    my $leadingNewline = '';
    my $trailingNewline = '';
    
    # Determine if we need to add a newline in front of the property declarations
    if (substr($headerFileContents, $indexAfterClosingBrace, 1) eq "\n")
    {
     $indexAfterClosingBrace += 1;
     $leadingNewline = '';
    }
    else
    {
     $leadingNewline = "\n";
    }
    
    # Determine if we need to add a newline after the property declarations
    if (substr($headerFileContents, $indexAfterClosingBrace, 9) eq '@property')
    {
     $trailingNewline = '';
    }
    else
    {
     $trailingNewline = "\n";
    }
    
    substr($headerFileContents, $indexAfterClosingBrace, 0) = $leadingNewline . $propertyDeclarations . $trailingNewline;
    
    my $replaceFileContentsScript = <<'REPLACEFILESCRIPT';
    on run argv
     set fileAlias to POSIX file (item 1 of argv)
     set newDocText to (item 2 of argv)
     tell application "Xcode"
      set doc to open fileAlias
      set text of doc to (text 1 thru -2 of newDocText)
     end tell
    end run
    REPLACEFILESCRIPT
    
    # Use Applescript to replace the contents of the header file
    # (I could have used the "Output" of the Xcode user script instead)
    system 'osascript', '-e', $replaceFileContentsScript, $headerFilePath, $headerFileContents;
    
    
    
    my $getFileContentsScript = <<'GETFILESCRIPT';
    on run argv
     set fileAlias to POSIX file (item 1 of argv)
     tell application "Xcode"
      set doc to open fileAlias
      set docText to text of doc
     end tell
     return docText
    end run
    GETFILESCRIPT
    
    # Get the contents of the implmentation file
    open(SCRIPTFILE, '-|') || exec 'osascript', '-e', $getFileContentsScript, $implementationFilePath;
    my $implementationFileContents = do {local $/; <SCRIPTFILE>};
    close(SCRIPTFILE);
    
    # Look for the class implementation statement
    if (length($implementationFileContents) && ($implementationFileContents =~ /(\@implementation [_A-Za-z][_A-Za-z0-9]*\n)/))
    {
     my $matchString = $1;
     my $indexAfterMatch = index($implementationFileContents, $matchString) + length($matchString);
    
     # Determine if we want a newline before the synthesize statement
     if (substr($implementationFileContents, $indexAfterMatch, 1) eq "\n")
     {
      $indexAfterMatch += 1;
      $leadingNewline = '';
     }
     else
     {
      $leadingNewline = "\n";
     }
    
     # Determine if we want a newline after the synthesize statement
     if (substr($implementationFileContents, $indexAfterMatch, 11) eq '@synthesize')
     {
      $trailingNewline = '';
     }
     else 
     {
      $trailingNewline = "\n";
     }
    
     substr($implementationFileContents, $indexAfterMatch, 0) = $leadingNewline. $synthesizeStatements . $trailingNewline;
    
     if ($implementationFileContents =~ /([ \t]*\[.*super.*dealloc.*\].*;.*\n)/)
     {  
      my $deallocMatch = $1;  
      my $indexAfterDeallocMatch = index($implementationFileContents, $deallocMatch);  
    
      substr($implementationFileContents, $indexAfterDeallocMatch, 0) = "$releaseStatements\n";  
    
     }
     elsif ($implementationFileContents =~ /(\@synthesize .*\n)*(\@synthesize [^\n]*\n)/s) {  
      my $synthesizeMatch = $2;  
       my $indexAfterSynthesizeMatch = index($implementationFileContents, $synthesizeMatch) + length($synthesizeMatch);  
      my $deallocMethod = "\n- (void)dealloc\n{\n$releaseStatements\n\t[super dealloc];\n}\n";  
    
      substr($implementationFileContents, $indexAfterSynthesizeMatch, 0) = $deallocMethod;  
     }
    
     # Use Applescript to replace the contents of the implementation file in Xcode
     system 'osascript', '-e', $replaceFileContentsScript, $implementationFilePath, $implementationFileContents;
    }
    
    exit 0;
    
    0 讨论(0)
提交回复
热议问题