什么是一些很好的Xcode脚本来加速开发?

时间:2009-06-23 16:55:38

标签: xcode scripting metaprogramming

Xcode允许您创建自动脚本以执行重复性任务。您编写了哪些脚本来加速开发?

6 个答案:

答案 0 :(得分:4)

我为JSON.Framework for Cocoa and the iPhone创建了三个。这些照顾以下内容:

  • 使用动态嵌入式框架,自定义iPhone SDK,API文档和一些文档文件创建发行版磁盘映像。
  • 在源上运行Doxygen以创建与Xcode兼容的文档集并安装它。这意味着当您在Xcode的文档搜索中搜索内容时,也可以找到您的文档。
  • 在源代码上运行Doxygen以更新源树本身中的API文档的签入版本。如果您使用Subversion(它假设),这非常简洁,因为您所在的分支机构的文档始终是最新的。例如,如果您在Google Code上托管,那就太棒了。

请注意下面的一些硬编码项目特定值。我不想通过编辑那些来破坏脚本。这些是从Xcode中的自定义脚本阶段启动的。您可以看到它们如何集成到上面链接的项目的Xcode项目中。

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

答案 1 :(得分:4)

这是Lawrence Johnston在上面发布的“Create Property and Synths for instance variables”脚本的改进。

设定:

输入:整个文档 目录:主目录 输出:丢弃输出 错误:忽略错误(如果你想看到它们,则发出警告)

选择任意数量的变量,它将为所有变量创建属性和syns。它甚至可以根据需要创建/编辑你的dalloc方法。

编辑结果,如果它们不完全正确(复制与保留等)

处理更多内容,如下划线存储名称,行为,dealloc,......

链接到它的来源和讨论: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;

答案 2 :(得分:2)

这是一个在任何时候记录方法及其参数的方法(通过带有左括号的谎言选择方法定义并执行脚本)。如果FIXME出现在输出中,则表示它是一种无法识别的类型。您可以将其添加到脚本中,也可以手动选择正确的格式说明符。

#!/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),

答案 3 :(得分:2)

这是为类创建-description方法的方法。突出显示实例变量声明部分(@interface ... {...})并执行脚本。然后将结果粘贴到您的实现中。我在GDB中使用了这个和po objectName。如果FIXME出现在输出中,则表示它是一种无法识别的类型。您可以将其添加到脚本中,也可以手动选择正确的格式说明符。

#!/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),

答案 4 :(得分:1)

这是我在其他地方找到的一个为实例变量创建@property(copy)和@synthesize属性指令的地方。它可以使用一些改进(比如,让你一次合成多个变量),但它比手工创建更好。

选择要为其创建属性的实例变量并激活脚本。

如果我想要(保留)而不是(复制)我只需要激活脚本并将其更改为手动保留(它足够聪明,不包括({copy})原始类型(例如int)以开始)。

#! /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;

答案 5 :(得分:0)

这将为您创建@ proptery,@ syntize,dealloc,viewDidUnload和公共方法。 Easy XCode集成:

http://github.com/holtwick/xobjc