用于生成/合成属性的 Xcode 脚本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1151393/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Xcode script for generating/synthesizing properties
提问by Lawrence Johnston
Does anybody have an Xcode script for generating @property and @synthsize directives for instance variables in a class?
有没有人有一个 Xcode 脚本来为类中的实例变量生成 @property 和 @synthsize 指令?
采纳答案by Dad
I use Accessorizer which does this and a whole lot more.
我使用 Accessorizer 来完成这个以及更多。
http://www.kevincallahan.org/software/accessorizer.html
http://www.kevincallahan.org/software/accessorizer.html
very inexpensive and powerful.
非常便宜且功能强大。
回答by Lawrence Johnston
This is the one I came up with based on one I found a long time ago, rewritten in Python and with the improvements that it can generate multiple properties at once, among other things.
这是我在很久以前找到的一个,用 Python 重写并改进它可以一次生成多个属性等的基础上提出的。
It will generate properties for all selected instance variable using (copy) as the attribute.
它将使用 (copy) 作为属性为所有选定的实例变量生成属性。
There are still some edge cases with multiple @interfaces or @implementations in a file, as well as some with unusual identifiers or asterisk placement (as in *const), but it should cover most typical coding styles. Feel free to edit/post modifications if you fix any of these cases.
仍然有一些边缘情况在一个文件中有多个 @interfaces 或 @implementations,还有一些具有不寻常的标识符或星号放置(如 *const),但它应该涵盖大多数典型的编码风格。如果您修复了这些情况中的任何一个,请随时编辑/发布修改。
#!/usr/bin/python
# Takes a header file with one or more instance variables selected
# and creates properties and synthesize directives for the selected properties.
# Accepts google-style instance variables with a tailing underscore and
# creates an appropriately named property without underscore.
# Entire Document
# Home Directory
# Discard Output
# Display in Alert
import os
import re
import subprocess
# AppleScripts for altering contents of files via Xcode
setFileContentsScript = """\
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 \
"""
getFileContentsScript = """\
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 \
"""
# Get variables from Xcode
headerFileText = """%%%{PBXAllText}%%%"""
selectionStartIndex = %%%{PBXSelectionStart}%%%
selectionEndIndex = %%%{PBXSelectionEnd}%%%
selectedText = headerFileText[selectionStartIndex:selectionEndIndex]
headerFilePath = """%%%{PBXFilePath}%%%"""
# Look for an implementation file with .m or .mm extension
implementationFilePath = headerFilePath[:-1] + "m"
if not os.path.exists(implementationFilePath):
implementationFilePath += "m"
instanceVariablesRegex = re.compile(
"""^\s*((?:(?:\w+)\s+)*(?:(?:\w+)))""" + # Identifier(s)
"""([*]?)\s*""" + # An optional asterisk
"""(\w+?)(_?);""", # The variable name
re.M)
# Now for each instance variable in the selected section
properties = ""
synthesizes = ""
for lineMatch in instanceVariablesRegex.findall(selectedText):
types = " ".join(lineMatch[0].split()) # Clean up consequtive whitespace
asterisk = lineMatch[1]
variableName = lineMatch[2]
trailingUnderscore = lineMatch[3]
pointerPropertyAttributes = "(copy) " # Attributes if variable is pointer
if not asterisk:
pointerPropertyAttributes = ""
newProperty = "@property %s%s %s%s;\n" % (pointerPropertyAttributes,
types,
asterisk,
variableName)
# If there's a trailing underscore, we need to let the synthesize
# know which backing variable it's using
newSynthesize = "@synthesize %s%s;\n" % (variableName,
trailingUnderscore and
" = %s_" % variableName)
properties += newProperty
synthesizes += newSynthesize
# Check to make sure at least 1 properties was found to generate
if not properties:
os.sys.stderr.writelines("No properties found to generate")
exit(-1)
# We want to insert the new properties either immediately after the last
# existing property or at the end of the instance variable section
findLastPropertyRegex = re.compile("^@interface.*?{.*?}.*?\n" +
"(?:.*^\s*@property.*?\n)?", re.M | re.S)
headerInsertIndex = findLastPropertyRegex.search(headerFileText).end()
# Add new lines on either side if this is the only property in the file
addedNewLine = "\n"
if re.search("^\s*@property", headerFileText, re.M):
# Not the only property, don't add
addedNewLine = ""
newHeaderFileText = "%s%s%s%s" % (headerFileText[:headerInsertIndex],
addedNewLine,
properties,
headerFileText[headerInsertIndex:])
subprocess.call(["osascript",
"-e",
setFileContentsScript,
headerFilePath,
newHeaderFileText])
if not os.path.exists(implementationFilePath):
os.sys.stdout.writelines("No implementation file found")
exit(0)
implementationFileText = subprocess.Popen(
["osascript",
"-e",
getFileContentsScript,
implementationFilePath],
stdout=subprocess.PIPE).communicate()[0]
# We want to insert the synthesizes either immediately after the last existing
# @synthesize or after the @implementation directive
lastSynthesizeRegex = re.compile("^\s*@implementation.*?\n" +
"(?:.*^\s*@synthesize.*?\n)?", re.M | re.S)
implementationInsertIndex = \
lastSynthesizeRegex.search(implementationFileText).end()
# Add new lines on either side if this is the only synthesize in the file
addedNewLine = "\n"
if re.search("^\s*@synthesize", implementationFileText, re.M):
# Not the only synthesize, don't add
addedNewLine = ""
newImplementationFileText = "%s%s%s%s" % \
(implementationFileText[:implementationInsertIndex],
addedNewLine,
synthesizes,
implementationFileText[implementationInsertIndex:])
subprocess.call(["osascript",
"-e",
setFileContentsScript,
implementationFilePath,
newImplementationFileText])
# Switch Xcode back to header file
subprocess.Popen(["osascript",
"-e",
getFileContentsScript,
headerFilePath],
stdout=subprocess.PIPE).communicate()
回答by Pat
This is a python script for Xcode 3.2.4 that generates; interface properties, implementation synthesize, and dealloc's. To install, copy this script, go to Xcode scripts menu (2nd to last) "Edit User Scripts..." Add it under Code, create a new script name, and paste the python script below.
这是生成的 Xcode 3.2.4 的 python 脚本;接口属性、实现综合和dealloc。要安装,请复制此脚本,转到 Xcode 脚本菜单(倒数第二个)“编辑用户脚本...”在代码下添加它,创建一个新的脚本名称,然后粘贴下面的 python 脚本。
To use just select the variables under the @interface, then call this script. It will then add all of the @property's, in the implementation and all of the @synthesize and dealloc's. It won't add IBOutlet to any of your Labels or Buttons since it doesn't know this, but this is easy to add manually.
要使用只需选择@interface 下的变量,然后调用此脚本。然后它将在实现中添加所有@property's,以及所有@synthesize 和 dealloc's。它不会将 IBOutlet 添加到您的任何标签或按钮,因为它不知道这一点,但这很容易手动添加。
Indentation of the script below is critical so don't change it.
下面脚本的缩进很重要,所以不要更改它。
#!/usr/bin/python
# Takes a header file with one or more instance variables selected
# and creates properties and synthesize directives for the selected properties.
# Accepts google-style instance variables with a tailing underscore and
# creates an appropriately named property without underscore.
# Xcode script options should be as follows:
# Entire Document
# Home Directory
# Discard Output
# Display in Alert
import os
import re
import subprocess
# AppleScripts for altering contents of files via Xcode
setFileContentsScript = """\
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 \
"""
getFileContentsScript = """\
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 \
"""
# Get variables from Xcode
headerFileText = """%%%{PBXAllText}%%%"""
selectionStartIndex = %%%{PBXSelectionStart}%%%
selectionEndIndex = %%%{PBXSelectionEnd}%%%
selectedText = headerFileText[selectionStartIndex:selectionEndIndex]
headerFilePath = """%%%{PBXFilePath}%%%"""
# Look for an implementation file with .m or .mm extension
implementationFilePath = headerFilePath[:-1] + "m"
if not os.path.exists(implementationFilePath):
implementationFilePath += "m"
instanceVariablesRegex = re.compile(
"""^\s*((?:(?:\b\w+\b)\s+)*(?:(?:\b\w+\b)))\s*""" + # Identifier(s)
"""([*]?)\s*""" + # An optional asterisk
"""(\b\w+?)(_?\b);""", # The variable name
re.M)
# Now for each instance variable in the selected section
properties = ""
synthesizes = ""
deallocs = ""
for lineMatch in instanceVariablesRegex.findall(selectedText):
types = " ".join(lineMatch[0].split()) # Clean up consequtive whitespace
asterisk = lineMatch[1]
variableName = lineMatch[2]
trailingUnderscore = lineMatch[3]
pointerPropertyAttributes = "(nonatomic, retain) " # Attributes if variable is pointer
if not asterisk:
pointerPropertyAttributes = "(nonatomic, assign) "
newProperty = "@property %s%s %s%s;\n" % (pointerPropertyAttributes,
types,
asterisk,
variableName)
# If there's a trailing underscore, we need to let the synthesize
# know which backing variable it's using
newSynthesize = "@synthesize %s%s;\n" % (variableName,
trailingUnderscore and
" = %s_" % variableName)
# only do the objects
if asterisk:
newDealloc = " [%s%s release];\n" % (variableName,
trailingUnderscore and
" = %s_" % variableName)
properties += newProperty
synthesizes += newSynthesize
# only add if it's an object
if asterisk:
deallocs += newDealloc
# Check to make sure at least 1 properties was found to generate
if not properties:
os.sys.stderr.writelines("No properties found to generate")
exit(-1)
# We want to insert the new properties either immediately after the last
# existing property or at the end of the instance variable section
findLastPropertyRegex = re.compile("^@interface.*?{.*?}.*?\n" +
"(?:.*^\s*@property.*?\n)?", re.M | re.S)
headerInsertIndex = findLastPropertyRegex.search(headerFileText).end()
# Add new lines on either side if this is the only property in the file
addedNewLine = "\n"
if re.search("^\s*@property", headerFileText, re.M):
# Not the only property, don't add
addedNewLine = ""
newHeaderFileText = "%s%s%s%s" % (headerFileText[:headerInsertIndex],
addedNewLine,
properties,
headerFileText[headerInsertIndex:])
subprocess.call(["osascript",
"-e",
setFileContentsScript,
headerFilePath,
newHeaderFileText])
if not os.path.exists(implementationFilePath):
os.sys.stdout.writelines("No implementation file found")
exit(0)
implementationFileText = subprocess.Popen(
["osascript",
"-e",
getFileContentsScript,
implementationFilePath],
stdout=subprocess.PIPE).communicate()[0]
# We want to insert the synthesizes either immediately after the last existing
# @synthesize or after the @implementation directive
lastSynthesizeRegex = re.compile("^\s*@implementation.*?\n" +
"(?:.*^\s*@synthesize.*?\n)?", re.M | re.S)
implementationInsertIndex = \
lastSynthesizeRegex.search(implementationFileText).end()
# Add new lines on either side if this is the only synthsize in the file
addedNewLine = "\n"
if re.search("^\s*@synthesize", implementationFileText, re.M):
# Not the only synthesize, don't add
addedNewLine = ""
newImplementationFileText = "%s%s%s%s" % \
(implementationFileText[:implementationInsertIndex],
addedNewLine,
synthesizes,
implementationFileText[implementationInsertIndex:])
subprocess.call(["osascript",
"-e",
setFileContentsScript,
implementationFilePath,
newImplementationFileText])
implementationFileText = subprocess.Popen(
["osascript",
"-e",
getFileContentsScript,
implementationFilePath],
stdout=subprocess.PIPE).communicate()[0]
# We want to insert the deallocs either immediately after the last existing
# [* release] or after the [super dealloc]
lastDeallocRegex = re.compile("^\s+\[super dealloc\];?\n" +
"(?:.*^\s+\[\w release\];?\n)?", re.M | re.S)
deallocInsertIndex = \
lastDeallocRegex.search(implementationFileText).end()
addedNewDeallocLine = "\n"
if re.search("^\s*\[\w release\];?", implementationFileText, re.M):
# Not the only dealloc, don't add
addedNewDeallocLine = ""
newImplementationFileText = "%s%s%s%s" % \
(implementationFileText[:deallocInsertIndex],
addedNewDeallocLine,
deallocs,
implementationFileText[deallocInsertIndex:])
subprocess.call(["osascript",
"-e",
setFileContentsScript,
implementationFilePath,
newImplementationFileText])
# Switch Xcode back to header file
subprocess.Popen(["osascript",
"-e",
getFileContentsScript,
headerFilePath],
stdout=subprocess.PIPE).communicate()
回答by Alex Gray
Whoa, there's a whole lot of crazy scripting goin' on here.
哇,这里有一大堆疯狂的脚本。
As of Xcode 4.4 (maybe before)... Your IVAR
s will be auto-synthesized.. For example..
从 Xcode 4.4(可能之前)开始......你的IVAR
s 将被自动合成......例如......
@property (assign) BOOL automatically;
@property (strong) NSArray *believeDat;
can be "accessored" via
可以通过“访问”
self.automatically = YES;
and edit the instance variable directly via the auto-generated-with-leading-underscore like..
并通过自动生成的前导下划线直接编辑实例变量,例如..
_believeDat = @["thank you, jesus", @"mary poopins"];
no @synthesize
necessary.
没有@synthesize
必要。
As for quick and easy entering of such @property
... drag the following, one at a time, into the "Code Snippet" library.. and you can assign keyboard shortcuts to insert these jump-off points for entering the properties more quickly. I use rrrfor objects and aaafor primitives.. but thats just me..
至于快速轻松地输入此类@property
......一次一个,将以下内容拖入“代码片段”库中......您可以分配键盘快捷键以插入这些跳转点,以便更快地输入属性。我rrr用于对象和aaa基元..但那只是我..
@property (nonatomic, assign) <#type#> <#name#>;
@property (nonatomic, assign) <#type#> <#name#>;
@property (nonatomic, retain) <#type#> *<#name#>;
@property (nonatomic, retain) <#type#> *<#name#>;
last but not least, and some may call me crazy.. but I throw the following macros into my .pch
to further expedite, clarify, and bring welcome brevity to the process.. all common macro disclaimers apply...
最后但并非最不重要的一点是,有些人可能会说我疯了……但我将以下宏放入我的程序中.pch
以进一步加快、澄清和简化流程……所有常见的宏免责声明都适用……
#define RONLY readonly
#define RDWRT readwrite
#define NATOM nonatomic
#define STRNG strong
#define ASS assign
#define CP copy
#define SET setter
#define GET getter
along with similarly structured #define
s for Apple classes ( #define NSA NSArray \ #define NSS NSString
), this makes things easier to read, and faster to enter (for me), looking like...
与#define
Apple 类 ( #define NSA NSArray \ #define NSS NSString
) 的类似结构s一起,这使内容更易于阅读,并且输入速度更快(对我而言),看起来像......
@property (NATOM, STRNG) NSA* fonts;
@property (NATOM, STRNG) NSS* cachedPath;
回答by AlfredBaudisch
回答by Kendall Helmstetter Gelner
Here is the userscript I currently use - it works on one instance variable at a time. It tries to use the right retain mechanism (simple types are not retained), and it also creates the @synthesize statement in the implementation file - currently it does not yet create dealloc statements for you.
这是我目前使用的用户脚本 - 它一次作用于一个实例变量。它尝试使用正确的保留机制(不保留简单类型),并且还在实现文件中创建 @synthesize 语句 - 目前它还没有为您创建 dealloc 语句。
#! /usr/bin/perl -w
#Input: Selection
#Directory: Selection
#Output: Display in Alert
#Errors: 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*$//;
return $string;
}
# Get the selection out of the header file
my $selectedText = substr $headerFileContents, $selectionStartIndex, ($selectionEndIndex - $selectionStartIndex);
#my $otherText = substr $headerFileContents, $selectionStartIndex;
#my $pulledText = "";
#if ( length($otherText) && $otherText =~ /.*$(^.*;).*/ )
#{
# $pulledText = ;
#}
#
#
#print $pulledText;
$selectedText = trim $selectedText;
my $type = "";
my $asterisk = "";
my $name = "";
my $behavior = "";
my $iboutlet = "";
# 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 = ;
$type = trim $type;
$asterisk = ;
$asterisk = trim $asterisk;
$name = ;
$behavior = "";
if (defined($asterisk) && length($asterisk) == 1)
{
$behavior = "(nonatomic, retain) ";
}
else
{
$behavior = "(nonatomic) ";
$asterisk = "";
}
}
else
{
print "Bailing, error in Regex";
exit 1;
}
# special case, see if we need to keep around an IBOUTLET declaration.
if ( length($selectedText) && ($selectedText =~ /IBOutlet/) )
{
$iboutlet = "IBOutlet ";
}
# 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 proper declaration
my $propertyDeclaration = $leadingNewline . "\@property " . $behavior . $iboutlet . $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 = ;
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;
回答by Kevin Callahan
Accessorizer http://www.kevincallahan.org/software/accessorizer.htmldoes this stuff and a lot more. It also handles custom prefixes and postfixes (suffixes). If you want Google's underscore, you got it. If you want to change it, change it on the fly - no need to edit scripts. Further, there's a defaults table where you can define default property specifiers based on the type of ivar passed in (copy, retain, readonly, assign etc) . It does IBOutlet detection and automatically inserts the IBOutlet keyword, nils out your views for -viewDidUnload, does several styles of dealloc. It also writes all those hairy accessors for collections (NSMutableArray and NSSet). It does key-archiving, various locking approaches, it can sort your property and synthesize blocks, write KVO code, Singleton code, convert to selector, generate HeaderDoc tags, NSLog() and more ... It also has a flexible styles tab for putting braces on newline or not, for spacing, for custom argument names etc. Most things are handled through Services, so you simply select your ivar block, hit a keystroke or two and you're done. If you minimize Accessorizer to the dock, its interface doesn't come to the front, allowing you to stay focused in Xcode or any other editor that supports Services. Of course, Accessorizer also writes out explicit accessors (as in Objective-C 1.0) and allows you to override properties - all with a simple toggle of a switch. You can even customize the override based on the type passed in. Watch the videos to see it in action.
配件http://www.kevincallahan.org/software/accessorizer.html做这些事情以及更多。它还处理自定义前缀和后缀(后缀)。如果你想要谷歌的下划线,你就知道了。如果您想更改它,请即时更改 - 无需编辑脚本。此外,还有一个默认表,您可以在其中根据传入的 ivar 类型(复制、保留、只读、分配等)定义默认属性说明符。它执行 IBOutlet 检测并自动插入 IBOutlet 关键字,清除您的 -viewDidUnload 视图,执行多种类型的 dealloc。它还为集合(NSMutableArray 和 NSSet)编写了所有这些毛茸茸的访问器。它进行密钥归档,各种锁定方法,它可以对您的财产进行排序并合成块,编写 KVO 代码,单例代码,转换为选择器,生成 HeaderDoc 标签,NSLog() 等等...... 它还有一个灵活的样式选项卡,用于是否在换行符上放置大括号、空格、自定义参数名称等。大多数事情都是通过服务处理的,因此您只需选择您的 ivar 块,敲击一两个键即可完成。如果您将 Accessorizer 最小化到 Dock,它的界面不会出现在前面,让您可以专注于 Xcode 或任何其他支持服务的编辑器。当然,Accessorizer 也写出显式访问器(如在 Objective-C 1.0 中)并允许您覆盖属性 - 所有这些都通过一个简单的开关切换。您甚至可以根据传入的类型自定义覆盖。观看视频以了解其实际效果。重做。如果您将 Accessorizer 最小化到 Dock,它的界面不会出现在前面,让您可以专注于 Xcode 或任何其他支持服务的编辑器。当然,Accessorizer 也写出显式访问器(如在 Objective-C 1.0 中)并允许您覆盖属性 - 所有这些都通过一个简单的开关切换。您甚至可以根据传入的类型自定义覆盖。观看视频以了解其实际效果。重做。如果您将 Accessorizer 最小化到 Dock,它的界面不会出现在前面,让您可以专注于 Xcode 或任何其他支持服务的编辑器。当然,Accessorizer 也写出显式访问器(如在 Objective-C 1.0 中)并允许您覆盖属性 - 所有这些都通过一个简单的开关切换。您甚至可以根据传入的类型自定义覆盖。观看视频以了解其实际效果。
回答by Pinochle
Here's one I wrote up yesterday to do the @property directives before coming across this question a few hours later. It's a simple text filter and would be trivial to extend it to @synthesize directives (add an appropriate when
clause to the case
statement and make appropriate additions to the when block_end
condition), and not much more work to extend it to handle multiple occurrences of @interface/@implementation in one file (by tracking their names --- it can be done through regexp captures, as everything else is in the script):
这是我昨天写的一个 @property 指令,然后在几个小时后遇到这个问题。这是一个简单的文本过滤器,将其扩展到@synthesize 指令(when
向case
语句中添加适当的子句并对when block_end
条件进行适当的添加)将是微不足道的,并且不需要做更多的工作来扩展它以处理@interface/@ 的多次出现在一个文件中实现(通过跟踪他们的名字——它可以通过正则表达式捕获来完成,因为其他一切都在脚本中):
#! /usr/bin/ruby
# -------------- Basic Definitions -----------------------------
doc = "%%%{PBXFilePath}%%%"
# regular expressions
search_exp = /[[:space:]]*([[a-zA-Z0-9]]*)[[:space:]]\*([a-zA-Z0-9]*)/
interface_start = /@interface/
block_end = /^\}/
#initializing variables
properties_list = []
properties_string = ""
reading_interface = 0
#---------------- Start Processing -----------------------------
file = File.open(doc, "r").readlines
file.each do |line|
# capture the regular expression matches only in the
# interface declaration and print out the matching
# property declarations
case line
# start capturing
when interface_start
reading_interface = 1
puts line
# capture and keep in properties_list
when search_exp
if (reading_interface == 1) then
data = Regexp.last_match
properties_list << data
end
puts line
# unpack properties_list and print out the property
# declarations
when block_end
if (reading_interface == 1) then
reading_interface = 0
properties_list.each do |pair|
properties_string << "@property (readwrite, copy) #{pair[0].lstrip};\n"
end
puts line
puts "\n" + properties_string
end
else puts line
end
end
I run this using "no input" and "replace document contents" as the options for I/O in the User Scripts editor.
我使用“无输入”和“替换文档内容”作为用户脚本编辑器中 I/O 的选项来运行它。