NSMutableArray as global var causes crash - objective-c

i have the following in the .h file as global var
NSMutableArray *garr;
and the below in the .m file
- (void)roundone {
if (!garr) {
garr = [[NSMutableArray alloc]init];
for (int x = 0; x < 900; x++) {
[garr addObject:[NSNumber numberWithInt: arc4random()%600]];
}
}
}
the problem in calling the var garr in any method however it returns the values in the nslog correctly but when i use the garr in the code the system crash!!! any ideas plz
-(IBAction)clicked:(id)sender{
NSLog(#"%#",garr);
//bubbleSort(array); // sort the array
int n = [garr count] ;
for (int i = 0; i < n-1; i++)
for (int j = 0; j < n-i-1; j++)
if ([[garr objectAtIndex: j] compare:[garr objectAtIndex: j+1]] ==
NSOrderedDescending)
//#define SWAP(arr, x, y)
do {
id oldX = [garr objectAtIndex: (j)];
// NSLog(#"%d %s",oldX ,oldX);
[garr replaceObjectAtIndex: (j) withObject: [garr objectAtIndex: (j+1)]];
[garr replaceObjectAtIndex: (j+1) withObject: oldX];
} while (0);
NSString *element;
NSEnumerator *iterator = [garr objectEnumerator];
while ((element = [iterator nextObject]) != nil)
NSLog(#"elments %#",element);
i dont what to complicate things in the code but the code works fine when the global var is inside the method but does not work when the garr outside the method

You should declare your global variables in the header, rather than defining them. Mark the variable extern, put a definition into a .m file, and initialize the variable to nil.
Header:
extern NSMutableArray *garr;
.m file:
NSMutableArray *garr = nil;
Rebuild everything, and the crash should be eliminated.

Related

MacOS - Activate a window given its Window ID

Is it possible to activate (bring to the fore) a window based on the values returned from CGWindowListCopyWindowInfo? (i.e Using the window ID (kCGWindowNumber) or something else.)
Edit:
I should specify that my app (which would run with accessibility permissions) needs to be able to do this for windows of other apps.
Since posting the question I've discovered AXUIElementPerformAction. Am I going in the right direction with this?
Or is running AppleScript bridge within my code the best approach?
You can attach to a process by pid and get its windows. Then use kAXRaiseAction to bring them to front, like this:
AXUIElementRef element = AXUIElementCreateApplication(pid);
if (element) {
CFArrayRef array;
AXUIElementCopyAttributeValues(element, kAXWindowsAttribute, 0, 99999, &array);
if (array == nullptr)
return;
NSArray *windows = (NSArray *)CFBridgingRelease(array);
for (NSUInteger i = 0; i < windows.count; ++i) {
AXUIElementRef ref = (__bridge AXUIElementRef)(windows[i]);
AXError error = AXUIElementPerformAction(ref, kAXRaiseAction);
// handle error
}
}
CFRelease(element);
No need to release array or windows. Children in arrays are handled automatically and the array is bridged to an NSArray which is released by ARC.
My answer's a little overcomplicated compared to what was already shared by Mike Lischke, but I've already posted it on a different SO question and I think it is a tiny bit closer to what you need:
#import <Cocoa/Cocoa.h>
#import <libproc.h>
#import <string.h>
#import <stdlib.h>
#import <stdio.h>
bool activate_window_of_id(unsigned long wid) {
bool success = false;
const CGWindowLevel kScreensaverWindowLevel = CGWindowLevelForKey(kCGScreenSaverWindowLevelKey);
CFArrayRef windowArray = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
CFIndex windowCount = 0;
if ((windowCount = CFArrayGetCount(windowArray))) {
for (CFIndex i = 0; i < windowCount; i++) {
NSDictionary *windowInfoDictionary = (__bridge NSDictionary *)((CFDictionaryRef)CFArrayGetValueAtIndex(windowArray, i));
NSNumber *ownerPID = (NSNumber *)(windowInfoDictionary[(id)kCGWindowOwnerPID]);
NSNumber *level = (NSNumber *)(windowInfoDictionary[(id)kCGWindowLayer]);
if (level.integerValue < kScreensaverWindowLevel) {
NSNumber *windowID = windowInfoDictionary[(id)kCGWindowNumber];
if (wid == windowID.integerValue) {
CFIndex appCount = [[[NSWorkspace sharedWorkspace] runningApplications] count];
for (CFIndex j = 0; j < appCount; j++) {
if (ownerPID.integerValue == [[[[NSWorkspace sharedWorkspace] runningApplications] objectAtIndex:j] processIdentifier]) {
NSRunningApplication *appWithPID = [[[NSWorkspace sharedWorkspace] runningApplications] objectAtIndex:j];
[appWithPID activateWithOptions:NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps];
char buf[PROC_PIDPATHINFO_MAXSIZE];
proc_pidpath(ownerPID.integerValue, buf, sizeof(buf));
NSString *buffer = [NSString stringWithUTF8String:buf];
unsigned long location = [buffer rangeOfString:#".app/Contents/MacOS/" options:NSBackwardsSearch].location;
NSString *path = (location != NSNotFound) ? [buffer substringWithRange:NSMakeRange(0, location)] : buffer;
NSString *app = [#" of application \\\"" stringByAppendingString:[path lastPathComponent]];
NSString *index = [#"set index of window id " stringByAppendingString:[windowID stringValue]];
NSString *execScript = [[index stringByAppendingString:app] stringByAppendingString:#"\\\" to 1"];
char *pointer = NULL;
size_t buffer_size = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
FILE *file = popen([[[#"osascript -e \"" stringByAppendingString:execScript] stringByAppendingString:#"\" 2>&1"] UTF8String], "r");
while (getline(&pointer, &buffer_size, file) != -1)
[array addObject:[NSString stringWithUTF8String:pointer]];
char *error = (char *)[[array componentsJoinedByString:#""] UTF8String];
if (strlen(error) > 0 && error[strlen(error) - 1] == '\n')
error[strlen(error) - 1] = '\0';
if ([[NSString stringWithUTF8String:error] isEqualToString:#""])
success = true;
[array release];
free(pointer);
pclose(file);
break;
}
}
}
}
}
}
CFRelease(windowArray);
return success;
}
The code it is based on does not work as advertised for its original purpose. Although, it did help me a lot to get working all the stuff I needed to answer this question. The code my answer is based on can be found here.

Iterating backwards over an array throwing exception

I am trying to make an add method that works like long addition, so I want to start the addition from the end and work my way backwards so I can get the carrys right and etc. So I am currently trying to start working backwards over the array.
For example what im trying to do.
two arrays with the character 123456789
and i want to add them starting at 9 + 9 then move to 8+8
So I'm pretty sure I'm using the right way to iterate backwards over an array, but everytime I try I get just the runtime error, index out of bounds, and I can't figure out why. Any help would be great, I just cant figure out why it keeps throwing the exception.
-(MPInteger *) add: (MPInteger *) x
{
NSMutableArray *a = self->intString;
NSMutableArray *b = x->intString;
NSMutableArray *c = [NSMutableArray arrayWithCapacity:100];
//for (int i = 0; i < [a count]; i++) {
for (NSInteger i = [a count] - 1; i > 0; i--) {
int num = 10;
NSNumber *ourNum = [NSNumber numberWithInt:num];
NSNumber *total = [NSNumber numberWithInt:[[a objectAtIndex:i] intValue] + [[b objectAtIndex:i] intValue]];
if ([total intValue] >= [ourNum intValue]) {
total = [NSNumber numberWithInt:([total intValue] - [ourNum intValue])];
[c addObject:[NSNumber numberWithInt:([total intValue])]];
} else {
[c addObject:[NSNumber numberWithInt:[[a objectAtIndex:i] intValue]+[[b objectAtIndex:i] intValue]]];
}
NSLog(#"%#", c[i]);
}
return x;
}
First, let's clean up this code.
- (MPInteger *)add:(MPInteger *)x {
NSMutableArray *a = self->intString;
NSMutableArray *b = x->intString;
NSMutableArray *c = [NSMutableArray arrayWithCapacity:100];
for (NSInteger i = [a count] - 1; i > 0; i--) {
int num = 10;
NSNumber *ourNum = #(num);
NSNumber *total = #([a[i] intValue] + [b[i] intValue]);
if ([total intValue] >= [ourNum intValue]) {
total = #([total intValue] - [ourNum intValue]);
[c addObject:#([total intValue])];
} else {
[c addObject:#([a[i] intValue] + [b[i] intValue])];
}
NSLog(#"%#", c[i]);
}
return x;
}
Next, let's remove redundant/duplicate code.
- (MPInteger *)add:(MPInteger *)x {
NSMutableArray *a = self->intString;
NSMutableArray *b = x->intString;
NSMutableArray *c = [NSMutableArray arrayWithCapacity:100];
for (NSInteger i = [a count] - 1; i > 0; i--) {
int num = 10;
NSNumber *total = #([a[i] intValue] + [b[i] intValue]);
if ([total intValue] >= num) {
total = #([total intValue] - num);
}
[c addObject:total];
NSLog(#"%#", c[i]);
}
return x;
}
Now we can clearly see all of the issues.
You're going from [a count] - 1 to 1. You should be going all the way to 0.
a and b might have different sizes, so if you only do [a count] - 1 to 0, then if for example [b count] < [a count], you'll get an index out of bounds error when you try to access b[i].
You're adding stuff to the end of c, but you should be adding it to the beginning of c since you're iterating backwards.
You don't store the carry anywhere.
You are accessing c[i], which doesn't exist.
You are starting with an empty array 'c', and you NSLog c[i] which is obviously out of bounds on the first iteration.

How can I create array of numbers in Objective-C?

i trying to create my firsy iphone program and i realize that making an array or matrix of 2 dims is difficult for me... :-(
*how and where i declarer somthing like this (take from java) so all the function can see it:
int[] myArray = new int[6];
*how can i trnslete this function:
public int[] sortArray (int[] myArray){
int tmp;
for (int x = 0; x < myArray.length; x++) {
for (int y = x+1; y < 6; y++) {
if (myArray[y] < myArray[x]) {
tmp = myArray[x];
myArray[x] = myArray[y];
myArray[y] = tmp;
}
}
}
return myArray;
}
*and how i call this function?
sortArray(myArray);
thanks for everyone!!!
sharon
You can do it with one line of code:
NSArray *array = #[#[#1, #2, #3],
#[#4, #5, #6],
#[#7, #8, #9]];
Learn about Objective-C literals here.
As in C,
int twoDArray[3][3];
In objective-C
NSArray *a=#[#"apple",#"axe",#"ant"];
NSArray *b=#[#"ball",#"book",#"baby"];
NSArray *c=#[#"cup",#"cat",#"cow"];
NSArray *twoDArray=#[a,b,c];
or in one statement:
NSArray *twoDArray=#[#[#"apple",#"axe",#"ant"],
#[#"ball",#"book",#"baby"],
#[#"cup",#"cat",#"cow"]];
EDIT:
NO need to convert that java function to obj-c method.
To sort the array :
NSArray *sortedArray = [array sortedArrayUsingComparator:^(id str1, id str2) {
return [((NSString *)str1) compare:((NSString *)str2) options:NSNumericSearch];
}];
EDIT 2: (Removed unwanted typecast of nsstring to id and back to string)
NSArray *sortedArray = [array sortedArrayUsingComparator:^(NSString *str1, NSString *str2) {
return [str1 compare:str2 options:NSNumericSearch];
}];
Declare in your respective .h file
NSMutableArray *numbers;
Then in your .m file
numbers = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < 6; i++)
[numbers addObject:[NSNumber numberWithInteger:i]];
and declare it in your .h as
-(NSMutableArray *)sortArray:(NSMutableArray *)numbers;
This is the translated method above in Objective-C:
-(NSMutableArray *)sortArray:(NSMutableArray *)numbers
{
NSInteger tmp = 0;
for(int x = 0; x < [numbers count]; x++)
for(int y = x + 1; y < 6; y++)
if([numbers objectAtIndex:y] < [numbers objectAtIndex:x])
{
tmp = [numbers objectAtIndex:x];
[numbers replaceObjectAtIndex:x withObject:[numbers objectAtIndex:y]];
[numbers replaceObjectAtIndex:y withObject:tmp];
}
return numbers;
}
Also you can call a method in objective-c as follows:
[self sortArray:numbers];
You seem to have (at least) two related-but separate questions here.
1/ how to create an array of numbers
Objective-C arrays come as immutable NSArrays (fixed contents) or mutable NSMutableArrays (you can add delete and shuffle contents around). You sort function as written is asking for a mutable array.
To create and populate an immutable array with NSNumber objects:
NSArray* array = #[#3,#5,#8,#2,#9,#1]; //"#1" is an NSNumber object literal
//access: array[3] etc
Multidimensional:
NSArray* arrayOfArrays #[#[#3,#5,#8],#[#2,#9,#1]];
//access: arrayOfArrays[1][2] etc
To create an empty variable-length mutable array
NSMutableArray* mutableArray = [[NSMutableArray alloc] init];
Create and populate a variable-length mutable array
myArray = [NSMutableArray arrayWithObjects:#3,#5,#8,#2,#9,#1, nil]; //note nil termination
To turn your immutable NSArray into a mutable NSMutableArray
NSMutableArray* mutableArray = [array mutableCopy];
(but take care, this will only render the top level as mutable, if it contains immutable subarrays they will remain immutable)
Objective-C collections (NSArray, NSDictionary, NSSet) can only hold objective-C objects. Therefore if you want to store ints or floats you need to box them into objective-C NSNumber objects before adding to a collection, and unbox them again to access the value.
int x;
float y;
NSNumber xNum = [NSNumber numberWithInt:x]; //box
NSNumber yNum = [NSNumber numberWithFloat:y]; //box
x = [xNum intValue]; //unbox
y = [yNum floatValue]; //unbox
2/ how to translate code
Here is a like-for-like translation:
To create the (mutable) myArray object:
NSMutableArray* myArray = [[NSMutableArray alloc] init];
Populate it:
[myArray addObjects:#3,#6,#8,#1,#9,nil]; //last value is nil to indicate termination
The method:
- sortArray:(NSMutableArray*)myArray
{
id tmp;
for (int x = 0; x < [myArray count]; x++) {
for (int y = x+1; y < 6; y++) {
if ([myArray[y] floatValue] < [myArray[x] floatValue]) {
tmp = myArray[x];
myArray[x] = myArray[y];
myArray[y] = tmp;
}
}
}
}
To call:
[self sortArray:myArray];
To declare with object scope, make a property in your #interface section
#interface myObject:NSObject
#property (nonatomic, strong) NSMutableArray* myArray;
#end
You will still need to create myArray before you can use it:
self.myArray = [[NSMutableArray alloc] init];
but you will be able to set and access it's values from anywhere inside the object thus:
self.myArray
And - if it is in the public header file #interface section - from outside the object thus:
myObject.myArray

Objective-C Why is this not working?

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSMutableString *outputStringSet = [[NSMutableString alloc] init];
NSMutableString *outputStringArray = [[NSMutableString alloc] init];
NSMutableSet *mySet = [[NSMutableSet alloc] init];
NSMutableArray *myArray = [[NSMutableArray alloc] initWithCapacity: 10];
int userInput;
NSLog(#"Enter 10 numbers");
for( int i = 0; i < 10; i++) {
scanf("%i", &userInput);
NSNumber *input = [[NSNumber alloc] initWithInt: userInput];
[myArray addObject:input];
if([mySet member: input]) {
[mySet addObject: input];
}
}
for (int k = 0; k < [myArray count]; k++) {
[outputStringArray appendFormat:#"%#, ", [myArray objectAtIndex:k]];
}
NSLog(#"%#", [outputStringArray substringToIndex:[outputStringArray length] - 2]);
for (int j = 0; j < [myArray count]; j++) {
if([mySet containsObject: [myArray objectAtIndex:j]]) {
[outputStringSet appendFormat:#"%#, ", [myArray objectAtIndex:j]];
}
NSLog(#"%#", outputStringSet);
}
}
return 0;
}
Code above prints the array but not the appropriate object in the set
Why?
Please explain clearly. I am a bit of a noob, and couldnt find the answer anywhere else.
thanks
if([mySet member: input]) {
[mySet addObject: input];
}
You're adding the object to the set if it’s already in it. You want the reverse: add the object if it's not in it.
Thus:
if ( ! [mySet member:input] )
[mySet addObject:input];
By the way, you should use containsObject: instead of member: in your test:
containsObject:
Returns a Boolean value that indicates whether a given
object is present in the set.
- (BOOL)containsObject:(id)anObject
Edit: you don't even need to test if the object is already in the set before adding it. After all, that's the main purpose of a NSSet: to ensure uniqueness of its objects. So if you add an object twice, the second call will silently be ignored, as the object is alreay in it.
Your set is empty because of
if([mySet member: input]) {
[mySet addObject: input];
}
member:
Determines whether the set contains an object equal to a given object,
and returns that object if it is present.

How to simplify my code... 2D NSArray in Objective C...?

self.myArray = [NSArray arrayWithObjects: [NSArray arrayWithObjects: [self generateMySecretObject], [self generateMySecretObject],nil], [NSArray arrayWithObjects: [self generateMySecretObject], [self generateMySecretObject],nil],nil];
for (int k=0; k<[self.myArray count]; k++) {
for(int s = 0; s<[[self.myArray objectAtIndex:k] count]; s++){
[[[self.myArray objectAtIndex:k] objectAtIndex:s] setAttribute:[self generateSecertAttribute]];
}
}
As you can see this is a simple 2*2 array, but it takes me lots of code to assign the NSArray in very first place, because I found that the NSArray can't assign the size at very beginning. Also, I want to set attribute one by one. I can't think of if my array change to 10*10. How long it could be. So, I hope you guys can give me some suggestions on shorten the code, and more readable. thz
(Some Assumptions: myArray will have a fixed size. It won't grown up or become smaller in the run time.)
Generate the array by -addObject:.
NSMutableArray* myArray = [NSMutableArray array];
for (int k = 0; k < 10; ++ k) {
NSMutableArray* subArr = [NSMutableArray array];
for (int s = 0; s < 10; ++ s) {
id item = (s == 0 && k == 0) ? [self d] : [self generateMySecretObject];
[item setAttribute:[self generateSecertAttribute]];
[subArr addObject:item];
}
[myArray addObject:subArr];
// use [myArray addObject:[[subArr copy] autorelease]] for deep immutability.
}
return [[myArray copy] autorelease];
(Don't query self.myArray many times. Each corresponds to an ObjC call and while someone calls an ObjC call is cheap, it's still not free.)
If the array is a fixed size and each row is the same length then you could uses a 1D array and an offset, EG:
int rowLength = 5;
int rowNumber = 0;
int columnNumber = 3;
[myArray objectAtIndex: (rowLength * rowNumber) + columnNumber];