Objective c 类,使它们在所有应用程序胶水中的所有类中可见。滑动方法名称应该避免与任何其他应用程序的粘合方法发生冲突的风险,尽管显然您仍然需要注意在正确的对象上调用它们,否则可能会得到意外的结果或错误
显然,对于iTunes 11中经过相同增强的任何其他属性,您都必须重复此修补程序,但至少完成一次,如果苹果在未来版本中恢复为整数,或者如果您忘记在复杂的开关块中包含以前的版本,您就不必再次更改它。当然,还有,您不必为生成多个iTunes标题而纠结:只需为当前版本创建一个标题,记住不要在代码中使用原始的Objective c 类,使它们在所有应用程序胶水中的所有类中可见。滑动方法名称应该避免与任何其他应用程序的粘合方法发生冲突的风险,尽管显然您仍然需要注意在正确的对象上调用它们,否则可能会得到意外的结果或错误,objective-c,macos,cocoa,casting,scripting-bridge,Objective C,Macos,Cocoa,Casting,Scripting Bridge,显然,对于iTunes 11中经过相同增强的任何其他属性,您都必须重复此修补程序,但至少完成一次,如果苹果在未来版本中恢复为整数,或者如果您忘记在复杂的开关块中包含以前的版本,您就不必再次更改它。当然,还有,您不必为生成多个iTunes标题而纠结:只需为当前版本创建一个标题,记住不要在代码中使用原始的-playerPosition和其他损坏的SB方法,而是使用自己强大的iTunes…方法每个玩家位置。i、 e player_Position=[自类型播送:(id)playerPosition];
-playerPosition
和其他损坏的SB方法,而是使用自己强大的iTunes…
方法每个玩家位置。i、 e player_Position=[自类型播送:(id)playerPosition];是的,我已经想到了这一点,但是我不需要强制转换属性playerPosition本身,而需要将iTunesApplication对象强制转换为正确的版本。但是,如果我需要强制转换多个不同类型的对象(甚至一个枚举),有没有办法复制版本检查代码?你能在回答中显示一个“如果”语句吗?当然,我会用我目前的方式更新我的帖子,我有点不喜欢。但我现在还不太清楚。也许我只是瞎了眼,把它变成了一个比实际情况更大的问题!非常感谢您的详细回答。非常感谢。这方面已经有点进展了,但正如我提到的,我认为会有一个更干净的方法。我想我会采用抽象类方法。对我来说是一次很好的训练。谢谢这样定义实现会有什么不同吗@implementation ITunesApplication(ITHack)
因为它已经是SBApplication
的子类了吗?如果我理解正确的话,它可能不会,但是根据用于ScriptingBridge
的实际应用程序头文件定义类别对我来说更有意义。谢谢你富有教育意义的回答。很高兴阅读并了解这些花絮。这不起作用,因为ObjC编译器需要在编译时将类别的方法注入类中,但SB直到运行时才生成粘合类(ITunesApplication、ITunesPlaylist等)。编译时唯一可用的具体类是SBObject、SBApplication和SBElementArray,因此只能对它们进行分类。不太令人满意,但正如我在其他地方所说的,SB既不是一个好的AppleScript公民,也不是一个好的ObjC公民,一旦你们开始认真对待它,就会在很多细节上失败。如果/当遇到太多麻烦时,请通过ASOC切换到AS。谢谢澄清。将考虑AS方法。
@property NSInteger playerPosition; // the player’s position within the currently playing track in seconds.
@property double playerPosition; // the player’s position within the currently playing track in seconds
sdef /path/to/application.app | sdp -fh --basename applicationName
[kiTunes_11_0_5 compare:versionInstalled options:NSNumericSearch]
if ([kiTunes_11_0_5 compare:_versionString options:NSNumericSearch] == NSOrderedSame) {
NSLog(@"%@, %@", kiTunes_11_0_5, _versionString);
playerPosition = [(iTunes_11_0_5_Application*)_iTunes playerPosition];
duration = [(iTunes_11_0_5_Track*)_currentTrack duration];
finish = [(iTunes_11_0_5_Track*)_currentTrack finish];
} else if [... and so on for each version to test and cast]
typedef enum { kEnumiTunes_11_0_5, ... } XYZiTunesVersion;
@implementation XYZiTunesHelper
{
ITunesAppObj *iTunes;
XYZiTunesVersion version;
}
- (id) initWith:(ITunesAppObj *)_iTunes version:(NSString *)_version
{
self = [super self];
if (self)
{
iTunes = _iTunes;
if ([kiTunes_11_0_5 compare:_version options:NSNumericSearch] == NSOrderedSame)
version = kEnumiTunes_11_0_5;
else ...
}
return self;
}
@interface XYZiTunesHelper : NSObject
@property double playerPosition;
...
@end
@implementation XYZiTunesHelper
// implement getter for playerPosition
- (double) playerPosition
{
switch (version)
{
case kEnumiTunes_11_0_5:
return [(iTunes_11_0_5_Application*)_iTunes playerPosition];
// other cases - by using an enum it is both fast and the
// compiler will check you cover all cases
}
}
// now implement the setter...
XYZiTunesHelper *_iTunesHelper = [[XYZiTunesHelper alloc] init:_iTunes
v ersion:_versionString];
...
playerPosition = [_iTunesHelper playerPosition];
duration = [_currentTrackHelper duration];
finish = [_currentTrackHelper finish];
tell app "iTunes" to get player position as real
ITApplication *iTunes = [ITApplication applicationWithBundleID: @"com.apple.itunes"];
NSError *error = nil;
double pos = [[iTunes playerPosition] getDoubleWithError: &error];
NSNumber *pos = [[iTunes playerPosition] getWithError: &error];
@implementation SBApplication (ITHack)
-(double)iTunes_playerPosition {
// Workaround for SB Fail: older versions of iTunes return typeInteger while newer versions
// return typeIEEE64BitFloatingPoint, but SB is too stupid to handle this correctly itself
// Build a reference to the 'player position' property using four-char codes from iTunes.sdef
SBObject *ref = [self propertyWithCode:'pPos'];
// Build and send the 'get' event to iTunes (note: while it is possible to include a
// keyAERequestedType parameter that tells the Apple Event Manager to coerce the returned
// AEDesc to a specific number type, it's not necessary to do so as sendEvent:id:parameters:
// unpacks all numeric AEDescs as NSNumber, which can perform any needed coercions itself)
NSNumber *res = [self sendEvent:'core' id:'getd' parameters: '----', ref, nil];
// The returned value is an NSNumber containing opaque numeric data, so call the appropriate
// method (-integerValue, -doubleValue, etc.) to get the desired representation
return [res doubleValue];
}
@end