This code had been working fine until just recently. I hadn't' changed anything nor upgraded my system and I'm completely flummoxed.
I've been using it for 6 years and now it dies on me.
Is there an easier or better way of running an applescript from within a cocoa application? At this point I'm happy to pay to fix this problem!
utils.h
#import <Foundation/Foundation.h>
#interface Utils : NSObject
// Runs an applescript with a given map of variables (name/value)
+ (NSArray *)runApplescript:(NSString *)source withVariables:(NSDictionary *)variables;
// Runs an applescript from a file pathwith a given map of variables
// (name/value)
+ (NSArray *)runApplescriptFromFile:(NSString *)scriptName withVariables:(NSDictionary *)variables;
+ (NSArray *)arrayFromDescriptor:(NSAppleEventDescriptor *)descriptor;
// String is empty or only has white characters (space, tab...)
+ (BOOL)stringIsEmptyOrWhite:(NSString *)string;
#end
Utils.M
#import "Utils.h"
#implementation Utils
+ (NSArray *)arrayFromDescriptor:(NSAppleEventDescriptor *)descriptor {
// Enumerate the apple descriptors (lists) returned by the applescript and
// make them into arrays
NSMutableArray *returnArray = [NSMutableArray array];
NSInteger counter, count = [descriptor numberOfItems];
for (counter = 1; counter <= count; counter++) {
NSAppleEventDescriptor *desc = [descriptor descriptorAtIndex:counter];
if (nil != [desc descriptorAtIndex:1]) {
[returnArray addObject:[Utils arrayFromDescriptor:desc]];
} else {
NSString *stringValue = [[descriptor descriptorAtIndex:counter] stringValue];
if (nil != stringValue) {
[returnArray addObject:stringValue];
} else {
[returnArray addObject:#""];
}
}
}
return returnArray;
}
+ (NSString *)escapeCharacters:(NSString *)string {
return [string stringByReplacingOccurrencesOfString:#"\"" withString:#"\\\""];
}
+ (NSArray *)runApplescript:(NSString *)source withVariables:(NSDictionary *)variables {
NSString *input = #"";
NSArray *variableNames = [variables allKeys];
// Transform the dictionary of names/values to set sentences of applescript
for (NSString *variableName in variableNames) {
NSObject *variableValue = [variables objectForKey:variableName];
if ([variableValue isKindOfClass:[NSString class]]) {
input =
[input stringByAppendingString:[NSString stringWithFormat:#"set %# to (\"%#\" as text)\n", variableName,
[Utils escapeCharacters:variableValue], nil]];
} else if ([variableValue isKindOfClass:[NSNumber class]]) {
input = [input stringByAppendingString:[NSString stringWithFormat:#"set %# to (%# as integer)\n",
variableName, variableValue, nil]];
} else if ([variableValue isKindOfClass:[NSArray class]]) {
// Initialize a list
NSString *entry;
NSArray *values = (NSArray *)variableValue;
input = [input stringByAppendingString:[NSString stringWithFormat:#"set %# to {", variableName]];
BOOL first = TRUE;
for (entry in values) {
if (!first) {
input = [input stringByAppendingString:#", "];
}
input = [input
stringByAppendingString:[NSString stringWithFormat:#"\"%#\"", [Utils escapeCharacters:entry], nil]];
first = FALSE;
}
input = [input stringByAppendingString:#"}\n"];
}
}
NSString *finalScript = [input stringByAppendingString:[NSString stringWithFormat:#"\n\n%#", source]];
NSLog(#"Final script: %#", finalScript);
NSAppleScript *script = [[NSAppleScript alloc] initWithSource:finalScript];
NSDictionary *error;
NSAppleEventDescriptor *descriptor = [script executeAndReturnError:&error];
NSLog(#"applescript error: %#", [error description]);
// Transform the return value of applescript to nested nsarrays
return [Utils arrayFromDescriptor:descriptor];
}
+ (NSArray *)runApplescriptFromFile:(NSString *)scriptName withVariables:(NSDictionary *)variables {
NSString *scriptPath = [[NSBundle mainBundle] pathForResource:scriptName ofType:#"applescript"];
NSString *scriptSource =
[[NSString alloc] initWithContentsOfFile:scriptPath encoding:NSASCIIStringEncoding error:nil];
return [Utils runApplescript:scriptSource withVariables:variables];
}
+ (BOOL)stringIsEmptyOrWhite:(NSString *)string {
string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return [string isEqualToString:#""];
}
#end
Easier, yes, although whether that’s your actual problem is another question.
http://appscript.sourceforge.net/asoc.html
I assume you’ve already got other details, including sandboxing and hardening settings and plist entries, taken care of. (Recent Xcode upgrades also had a habit of breaking it when auto-upgrading your project files, by turning on hardening for you so Apple events can’t get out.)
I have a search bar for my table view and until now I used a predicate to check if the data array contains the search bar value. But now there are objects in my data array and now I don't know how to use the predicate. Here is my code:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF contains [cd] %#", self.controller.searchBar.text];
NSMutableArray *temp = [[NSMutableArray alloc] init];
for (int i = 0; i < [self.data count]; i++) {
Student *student = [[Student alloc] initWithIdentifier:[[self.data objectAtIndex:self.tableView.indexPathForSelectedRow.row] objectForKey:#"id"] name:[[self.data objectAtIndex:self.tableView.indexPathForSelectedRow.row] objectForKey:#"name"] is_public:[[self.data objectAtIndex:self.tableView.indexPathForSelectedRow.row] objectForKey:#"is_public"] password:[[self.data objectAtIndex:self.tableView.indexPathForSelectedRow.row] objectForKey:#"passwort"]];
[temp addObject:student];
}
self.results = [temp filteredArrayUsingPredicate:predicate];
Now it compares the search bar value with the object. But it should compare the search bar value with object.name. How can I do this?
EDIT:
The Student code:
#implementation Student
- (id)initWithIdentifier:(NSString *)identifier name:(NSString *)name is_public:(NSString *)is_public password:(NSString *)password {
self= [super init];
if( self ) {
self.identifier = identifier;
self.name = name;
self.is_public = is_public;
self.password = password;
}
return self;
}
- (NSDictionary*)writableRepresentation {
NSMutableDictionary *writableRepresentation= [NSMutableDictionary dictionaryWithCapacity:4];
[writableRepresentation setValue:self.identifier forKey:#"Identifier"];
[writableRepresentation setValue:self.name forKey:#"Name"];
[writableRepresentation setValue:self.is_public forKey:#"is_public"];
[writableRepresentation setValue:self.password forKey:#"password"];
return writableRepresentation;
}
+ (Student*)studentFromDictionary:(NSDictionary*)dictionaryRepresentation {
return [[Tipprunde alloc] initWithIdentifier:[dictionaryRepresentation valueForKey:#"Identifier"] name:[dictionaryRepresentation valueForKey:#"Name"] is_public:[dictionaryRepresentation valueForKey:#"is_public"] password:[dictionaryRepresentation valueForKey:#"password"]];
}
#end
It don't seem to work with SELF.name. I get the following error:
-[Student objectForKey:]: unrecognized selector sent to instance...
I want to test some cases in my app with strings which have the same hash, and I can't find it =(
I've found two strings with the same MD5. here But their hash are different. And googling didn't help me =(
NSString(MD5) category
Little story about NSDictionary
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSString *string1 = [self fileContentWithName:#"message1" encoding:NSUnicodeStringEncoding];
NSString *string2 = [self fileContentWithName:#"message2" encoding:NSUnicodeStringEncoding];
if (string1 != nil) {
if (string1.hash == string2.hash) {
NSLog(#"Hashes are the same");
} else {
if ([[string1 MD5Hash] isEqualToString:[string2 MD5Hash]]) {
NSLog(#"MD5 hases are equalfor:");
NSLog(#"lenght = %3ld - %#", string1.length, string1);
NSLog(#"lenght = %3ld - %#", string2.length, string2);
if ([string1 isEqualToString:string2]) {
NSLog(#"Strings are equal too");
} else {
NSLog(#"But strings are not equal");
}
}
}
}
}
#pragma mark -
- (NSString*)fileContentWithName:(NSString*)name encoding:(NSStringEncoding)enc
{
NSString *txtFilePath1 = [[NSBundle mainBundle] pathForResource:name ofType:#"bin"];
NSError *error = nil;
NSString *txtFileContents1 = [NSString stringWithContentsOfFile:txtFilePath1 encoding:enc error:&error];
return txtFileContents1;
}
Based on the accepted answer to this question I wrote the following code:
NSData* somedata;
somedata=[NSKeyedArchiver archivedDataWithRootObject:ts];
where ts is an NSAttributedString that is populated with some text and some attributes (colors, in this case).
When I execute this code, I receive this error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x6eb5b90'
I'm new to the NSCoder arena, but the answer to the aforementioned question made it seem like this is all I have to do. Is it? Did I miss something?
EDIT:
The unrecognized selector in this case is being sent to a color attribute in the NSAttributedString. When I initialize the string like so:
NSAttributedString *ts = [[NSAttributedString alloc] initWithString:text attributes:self.currentAttributeDictionary];
The dictionary is built like so:
self.currentAttributeDictionary=[NSDictionary dictionaryWithObjectsAndKeys:
[self.currentColor CGColor],(NSString*)kCTForegroundColorAttributeName,
nil];
And an NSLog of the dictionary yields this:
New dictionary is: {
CTForegroundColor = "<CGColor 0x6eb5b90> [<CGColorSpace 0x6e968c0> (kCGColorSpaceDeviceRGB)] ( 1 1 0 1 )";}
The address of the CGColor, above, matches the address in the error message.
While UIColor conforms to NSCoding, it is (unlike most such classes) not toll-free bridged to CGColorRef. Your dictionary is attempting to encode its contents, and CGColorRef doesn't know how to encode itself.
Presuming that you don't want to encode a UIColor instead (since these sound like Core Text attributes), you are going to have to handle serialization of the CGColorRef yourself. See, for example, this question for some useful thoughts.
It should be noted, btw, since I don't know where the archived data is going, that if you want to unarchive the data on OS X that colors again become a headache at the AppKit/UIKit level: NSColor and UIColor are not directly compatible, so you would still need to go via CGColorRef, stashing the color space information as appropriate.
As requested, here's the code I used to accomplish what i needed to accomplish. It's been a year since I looked at this code, and it was written more to understand what was going on than for great coding practices or for any sort of efficiency. However, it did work, and it worked great!
I defined a category of NSAttributedString code is below.
Example use:
-(void)code:(id)sender {
self.testData=[textView.attributedString customEncode];
NSLog(#"%#",self.testData);
}
-(void)recover:(id)sender {
NSAttributedString* tString=[NSMutableAttributedString customDecode:self.testData];
NSLog(#"Recover pressed: %#",tString);
textView.attributedString=tString;
}
And here's the underlying code:
#import "NSAttributedString+Extras.h"
#import <CoreText/CoreText.h>
#implementation NSAttributedString (Extras)
-(NSData*)customEncode {
__block NSMutableArray* archivableAttributes=[[NSMutableArray alloc]init];
[self enumerateAttributesInRange:NSMakeRange(0, [self length]) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
NSLog(#"range: %d %d",range.location, range.length);
NSLog(#"dict: %#",attrs);
NSLog(#"keys: %#", [attrs allKeys]);
NSLog(#"values: %#", [attrs allValues]);
NSMutableDictionary* tDict=[[NSMutableDictionary alloc]init];
[tDict setObject:[NSNumber numberWithInt:range.location] forKey:#"location"];
[tDict setObject:[NSNumber numberWithInt:range.length] forKey:#"length"];
for (NSString* tKey in [attrs allKeys]) {
if ([tKey isEqualToString:#"CTUnderlineColor"]) {
[tDict setObject:[NSAttributedString arrayFromCGColorComponents:((CGColorRef)[attrs objectForKey:#"CTUnderlineColor"])] forKey:#"CTUnderlineColor"];
}
if ([tKey isEqualToString:#"NSUnderline"]) {
NSNumber* underline=[attrs objectForKey:#"NSUnderline"];
[tDict setObject:underline forKey:#"NSUnderline"];
}
if ([tKey isEqualToString:#"CTForegroundColor"]) {
[tDict setObject:[NSAttributedString arrayFromCGColorComponents:((CGColorRef)[attrs objectForKey:#"CTForegroundColor"])] forKey:#"CTForegroundColor"];
}
if ([tKey isEqualToString:#"NSFont"]) {
CTFontRef font=((CTFontRef)[attrs objectForKey:#"NSFont"]);
NSDictionary* fontDict=[NSDictionary
dictionaryWithObjects:
[NSArray arrayWithObjects:(NSString*)CTFontCopyPostScriptName(font),[NSNumber numberWithFloat:CTFontGetSize(font)], nil]
forKeys:
[NSArray arrayWithObjects:#"fontName", #"fontSize", nil]];
[tDict setObject:fontDict forKey:#"NSFont"];
}
}
[archivableAttributes addObject:tDict];
}];
NSMutableDictionary* archiveNSMString=[NSMutableDictionary
dictionaryWithObjects: [NSArray arrayWithObjects:[self string],archivableAttributes,nil]
forKeys:[NSArray arrayWithObjects:#"string",#"attributes",nil]];
NSLog(#"archivableAttributes array: %#",archiveNSMString);
NSData* tData=[NSKeyedArchiver archivedDataWithRootObject:archiveNSMString];
NSLog(#"tdata: %#",tData);
return tData;
}
+(NSAttributedString*)customDecode:(NSData *)data {
NSMutableAttributedString* tString;
NSMutableDictionary* tDict=[NSKeyedUnarchiver unarchiveObjectWithData:data];
NSArray* attrs;
CTFontRef font=NULL;
CGColorRef color=NULL;
NSNumber* underlineProp=[NSNumber numberWithInt:0];
CGColorRef underlineColor=NULL;
NSLog(#"decoded dictionary: %#",tDict);
if ([[tDict allKeys]containsObject:#"string"]) {
tString=[[NSMutableAttributedString alloc]initWithString:((NSString*)[tDict objectForKey:#"string"])];
}
else {
tString=[[NSMutableAttributedString alloc]initWithString:#""];
}
if ([[tDict allKeys]containsObject:#"attributes"]) {
attrs=[tDict objectForKey:#"attributes"];
}
else {
attrs=nil;
}
for (NSDictionary* attDict in attrs) {
int location=-1;
int length=-1;
NSRange insertRange=NSMakeRange(-1, 0);
if ([[attDict allKeys]containsObject:#"location"]) {
location=[[attDict objectForKey:#"location"]intValue];
}
if ([[attDict allKeys]containsObject:#"length"]) {
length=[[attDict objectForKey:#"length"]intValue];
}
if (location!=-1&&length!=-1) {
insertRange=NSMakeRange(location, length);
}
if ([[attDict allKeys]containsObject:#"NSUnderline"]) {
underlineProp=[attDict objectForKey:#"NSUnderline"];
}
if ([[attDict allKeys]containsObject:#"CTUnderlineColor"]) {
underlineColor=[NSAttributedString cgColorRefFromArray:[attDict objectForKey:#"CTUnderlineColor"]];
}
if ([[attDict allKeys]containsObject:#"CTForegroundColor"]) {
color=[NSAttributedString cgColorRefFromArray:[attDict objectForKey:#"CTForegroundColor"]];
}
if ([[attDict allKeys]containsObject:#"NSFont"]) {
NSString* name=nil;
float size=-1;
NSDictionary* fontDict=[attDict objectForKey:#"NSFont"];
if ([[fontDict allKeys]containsObject:#"fontName"]) {
name=[fontDict objectForKey:#"fontName"];
}
if ([[fontDict allKeys]containsObject:#"fontSize"]) {
size=[[fontDict objectForKey:#"fontSize"]floatValue];
}
if (name!=nil&&size!=-1) {
font=CTFontCreateWithName((CFStringRef)name, size, NULL);
}
}
if (insertRange.location!=-1) {
if (color!=NULL) {
[tString addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)color range:insertRange];
}
if (font!=NULL) {
[tString addAttribute:(NSString*)kCTFontAttributeName value:(id)font range:insertRange];
}
if ([underlineProp intValue]!=0&&underlineColor!=NULL) {
[tString addAttribute:(NSString*)kCTUnderlineColorAttributeName value:(id)underlineColor range:insertRange];
[tString addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:(id)underlineProp range:insertRange];
}
}
}
[tString enumerateAttributesInRange:NSMakeRange(0, [tString length]) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
NSLog(#"range: %d %d",range.location, range.length);
NSLog(#"dict: %#",attrs);
NSLog(#"keys: %#", [attrs allKeys]);
NSLog(#"values: %#", [attrs allValues]);
}];
return [[NSAttributedString alloc]initWithAttributedString:tString];
}
+(NSArray*)arrayFromCGColorComponents:(CGColorRef)color {
int numComponents=CGColorGetNumberOfComponents(color);
CGFloat* components=CGColorGetComponents(color);
NSMutableArray* retval=[[NSMutableArray alloc]init];
for(int i=0;i<numComponents;i++) {
[retval addObject:[NSNumber numberWithFloat:components[i]]];
}
return [NSArray arrayWithArray:retval];
}
+(CGColorRef)cgColorRefFromArray:(NSArray*)theArray {
CGFloat* array=malloc(sizeof(CGFloat)*[theArray count]);
for (int i=0; i<[theArray count]; i++) {
array[i]=[[theArray objectAtIndex:i]floatValue];
}
CGColorSpaceRef theSpace;
if ([theArray count]==2) {
theSpace=CGColorSpaceCreateDeviceGray();
}
else {
theSpace=CGColorSpaceCreateDeviceRGB();
}
return CGColorCreate(theSpace, array);
}
#end
hi at all ,I've this code :
+(NSArray *)splatterUrls
{
NSString *jsonString = [ ApiMethod jsonOfStores];
NSDictionary *results =[jsonString objectFromJSONString];
NSArray *movieArray = [results objectForKey:#"Seasons"];
//int i=0;
// Search for year to match
for (NSDictionary *movie in movieArray)
{
NSNumber *idSplatterMovie = [movie objectForKey:#"Id"];
// NSLog(#" %#", idSplatterMovie );
NSArray *try = [movie objectForKey:#"Episodes"];
// NSLog(#"%#", try);
for (NSDictionary *op in try)
{
if([idSplatterMovie integerValue] == 46)
{
//i++;
NSArray *movieArrayString = [op objectForKey:#"Url"];
// NSLog(#" %#", movieArrayString);
return movieArrayString;
}
}
}
}
I want to return movieArrayString with all his objects and how many object contains in it. I think that I should use this method : + (id)arrayWithObjects:(const id *)objects count:(NSUInteger)count. It's possible? If yes, can you tell me how can use it?
Thank you so much!
by the way , i have to call splatterUrls method and implement in home.m that it is :
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *urlSplatter= [GetSplatterUrlsMovie splatterUrls];
NSLog(#" %#", urlSplatter);
}
Looks good as it is to me.
Do this to return your movies array, array will be equal to your movies array:
NSArray *array = [self splatterUrls];
Then to get the count/number of objects in your array do this, i is equal to the number of objects in the array:
int i = [array count];
What is the problem ??
You return a NSarray ... call the method count on your NSarray object!