Finding name of inserted CD in Cocoa - cocoa

I had a bookmark which described the process on how to do this - finding the name of a mounted CD in OS X - but I deleted the bookmark when I reformatted my Mac. :P
Reading up on the subject, this is what I think might work. Basically, I need to verify if a particular CD is mounted before continuing in the application
Access NSWorkspace
Perform 'checkForRemovableMedia'
Grab array of mounted media paths from 'mountedRemoveableMedia'
Run through array of mounted media paths to find one containing name of targeted disc
Anyway, this is what I've came up with as a possible solution. Anyone else have any other ideas/knowledge in this area in Cocoa? Suggestions :)
EDIT:
I made this code below, but isn't working. It creates an NSCFArray which contains NSCFStrings, which I read up and shouldn't be doing.
NSArray *mountedItems = [[NSWorkspace sharedWorkspace] mountedRemovableMedia];
int count = [mountedItems count];
int i = 0;
for (i = 0; i < count; i++) {
//line is not printing. contains NSCFArray and NSCFStrings
[NSLog print:[[mountedItems objectAtIndex:i] stringValue]];
}

OK, so I'm an idiot.
[[NSWorkspace sharedWorkspace] checkForRemovableMedia];
NSArray *mountedItems = [[NSWorkspace sharedWorkspace] mountedRemovableMedia];
NSUInteger count = [mountedItems count];
NSUInteger i = 0;
for (i = 0; i < count; i++) {
NSString *tempString = [mountedItems objectAtIndex:i];
NSLog(#"%#",tempString);
}
I was not only using NSLog wrong, but completely didn't even realize that perhaps calling 'stringValue' on a string is redundant. And also what caused the code to break. :P
This works now; I also added 'checkForRemovableMedia' as an extra precaution.

Related

How to use "valueforkey"?

I'm trying to do the following - I have an Array in which some strings are stored. These strings shall be used to call an NSArray. An example will clarify what I'm trying to do:
This is the working code that I'm trying to achieve ("briefing0" is of type NSArray):
NSString *path = [docsDir stringByAppendingPathComponent:[briefing0 objectAtIndex:indexPath.row]];
This is the "same" code that I'm trying to use:
int i = 0;
NSString *path = [docsDir stringByAppendingPathComponent:[(NSArray *)[NSString stringWithFormat:#"briefing%d", i] objectAtIndex:indexPath.row]];
Any ideas?
Thanks in advance!
Tom
Assuming that briefing0 is actually a property, then yes, this is possible (and not uncommon) in ObjC via KVC.
int i = 0;
NSString *prop = [NSString stringWithFormat:#"briefing%d", i];
NSArray *array = [self valueForKey:prop];
NSString *value = [array objectAtIndex:indexPath.row];
... etc. ...
-valueForKey: is the piece you're looking for. Note that this will throw an exception if you construct a key that does not exist, and so must be used with extreme care.

pointer being freed was not allocated -- how to debug in Xcode objective c?

I need some help understanding how to use the debugging tools -- the previous posts on this topic suggest using NSZombie and setting breakpoints. These are not working for me, meaning I don't understand how to use them properly -- or how to interpret what they are telling me.
(I'm operating in a vacuum, basically -- no one in my workplace or social circle does objective c programming...)
Here's the offending code. My idea is to make moving array of 100 objects. The routine motionDataArray is called by the motionManager startDeviceMotionUpdatesUsingReferenceFrame method. The array gets populated and when its length reaches 100 it has the first object removed so there will always only ever be 100 objects in the array. This way, I figure, I can take the mean of the data and get rid of a lot of the noise.
(I imagine there is probably a better way to achieve this goal, but here is what I've come up with...)
- (void) motionDataArray: (CMCalibratedMagneticField) field
{
NSDictionary *motionData = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble: motionManager.deviceMotion.gravity.x],#"gravity_x",
[NSNumber numberWithDouble: motionManager.deviceMotion.gravity.y],#"gravity_y",
[NSNumber numberWithDouble: motionManager.deviceMotion.gravity.z],#"gravity_z",
[NSNumber numberWithDouble: field.field.x],#"mag_x",
[NSNumber numberWithDouble: field.field.y],#"mag_y",
[NSNumber numberWithDouble: field.field.z],#"mag_z",
[NSNumber numberWithDouble: `enter code here`locationManager.heading.magneticHeading],#"mag_heading",
[NSNumber numberWithDouble: motionManager.deviceMotion.attitude.roll],#"roll",
[NSNumber numberWithDouble: motionManager.deviceMotion.attitude.yaw],#"yaw",
[NSNumber numberWithDouble: motionManager.deviceMotion.attitude.pitch],#"roll",
nil];
//NSLog(#"%d",[motionArray count]);
if([timerArray count] > arrayCount - 1)
{
int i = [timerArray count] - arrayCount;
for (int j = 0; j < i + 1; j++)
{
[motionArray removeObjectAtIndex:0];
}
}
[motionArray addObject:motionData];
}
The code runs fine for the first two hundred iterations or so, and then comes the crash and the error: pointer being freed was not allocated.
Any good pointers on how to interpret the output from Instruments or anyother debugging methodology would be great help for me, and I'm sure for others out there too. Many thanks in advance...
Tim Redfield
OK, I think I have a solution -- it runs without crashing and the array stays at the 100 maximum. But, I don't really understand WHY it works. It seems the array cannot have an object removed from it, unless #synchronize is used, as follows:
if([timerArray count] > arrayCount - 1)
{
int i = [timerArray count] - arrayCount;
for (int j = 0; j < i + 1; j++)
{
#synchronized(timerArray) {
[timerArray removeObjectAtIndex:0];
}
}
}
I guess this has to do with the array having an object removed before it is allocated, which seems to happen because the code loop is not necessarily running at the same speed as the motionManager is pushing the data. I am still trying to wrap my head around this. Comments welcomed!

NSArray out of bounds check

noobie question.. What is the best way to check if the index of an NSArray or NSMutableArray exists. I search everywhere to no avail!!
This is what I have tried:
if (sections = [arr objectAtIndex:4])
{
/*.....*/
}
or
sections = [arr objectAtIndex:4]
if (sections == nil)
{
/*.....*/
}
but both throws an "out of bounds" error not allowing me to continue
(do not reply with a try catch because thats not a solution for me)
Thanks in advance
if (array.count > 4) {
sections = [array objectAtIndex:4];
}
If you have an integer index (e.g. i), you can generally prevent this error by checking the arrays bounds like this
int indexForObjectInArray = 4;
NSArray yourArray = ...
if (indexForObjectInArray < [yourArray count])
{
id objectOfArray = [yourArray objectAtIndex:indexForObjectInArray];
}
Keep in mind NSArray is in sequential order from 0 to N-1 items
Your are trying to access item which has exceeded limit and a array is nil then compiler would throw out of bound error.
EDIT : #sch's answer above shows how can we check if NSArray has required ordered item present in it or not.
You can use the MIN operator to fail silently like this [array objectAtIndex:MIN(i, array.count-1)], to either get next object in the array or the last. Can be useful when you for example want to concatenate strings:
NSArray *array = #[#"Some", #"random", #"array", #"of", #"strings", #"."];
NSString *concatenatedString = #"";
for (NSUInteger i=0; i<10; i++) { //this would normally lead to crash
NSString *nextString = [[array objectAtIndex:MIN(i, array.count-1)]stringByAppendingString:#" "];
concatenatedString = [concatenatedString stringByAppendingString:nextString];
}
NSLog(#"%#", concatenatedString);
Result: "Some random array of strings . . . . . "

Search By Number and Get the image using ABAddressBook

I wish to search in the iphone AddressBook through my app using the number as the key and then retrieve the image associated to that contact and display it on the UIImageView.
I tried using ABAddressBook framework but was clueless to proceed.
Can anyone please suggest me the solutions or any alternative path that I can follow. Any code snippet would also be of great help!!
Any form of help would be highly appreciable.
Thanks in advance
The AB framework can be a real pain at times. But it breaks down to a series of pretty simple operations. First, you have to create an ABAddressBook instance:
ABAddressBookRef addressbook = ABAddressBookCreate();
Then you'll want to make a copy of the array of all people in the address book, and step through them looking for the data you want:
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressbook);
CFIndex numPeople = ABAddressBookGetPersonCount(addressbook);
for (int i=0; i < numPeople; i++) {
Inside your loop, you'll probably want to get a reference to the individual person:
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
Then you want to compare the number you have (lets call that inNumber) to every phone number associated with that particular person. To do that, you first need a list of all the person's phone numbers:
ABMutableMultiValueRef phonelist = ABRecordCopyValue(person, kABPersonPhoneProperty);
Then, of course, you'll need to have an inner loop that loops over each of the individual person's phone numbers:
CFIndex numPhones = ABMultiValueGetCount(phones);
for (int j=0; j < numPhones; j++) {
Since the phone numbers have both numbers and labels associated with them, you'll need to extract the actual phone number string as an NSString:
CFTypeRef ABphone = ABMultiValueCopyValueAtIndex(phoneList, j);
NSString *personPhone = (NSString *)ABphone;
CFRelease(ABphone);
Now you can finally compare numbers! Do so with the standard NSString comparison methods, but remember that you need to worry about formatting, etc.
Once you find the person who has a phone number matching inNumber, you'll want the extract that person's image into a UIImage:
CFDataRef imageData = ABPersonCopyImageData(person);
UIImage *image = [UIImage imageWithData:(NSData *)imageData];
CFRelease(imageData);
When it comes time to exit, you'll need to clean up memory. A general rule of thumb for the AB framework is that anything with Get in the function name you don't need to release, and anything with Copy or Create, you do need to release. So, in this case you'll need to CFRelease() phonelist, allPeople, and addressbook, but not numPeople, person, or numPhones.
-(void)fetchAddressBook:(NSString *)searchnumber
{
ABAddressBookRef UsersAddressBook = ABAddressBookCreateWithOptions(NULL, NULL);
//contains details for all the contacts
CFArrayRef ContactInfoArray = ABAddressBookCopyArrayOfAllPeople(UsersAddressBook);
//get the total number of count of the users contact
CFIndex numberofPeople = CFArrayGetCount(ContactInfoArray);
//iterate through each record and add the value in the array
for (int i =0; i<numberofPeople; i++) {
ABRecordRef ref = CFArrayGetValueAtIndex(ContactInfoArray, i);
NSString *firstName = (__bridge NSString *)ABRecordCopyValue(ref, kABPersonFirstNameProperty);
//Get phone no. from contacts
ABMultiValueRef multi = ABRecordCopyValue(ref, kABPersonPhoneProperty);
UIImage *iimage;
NSString* phone;
for (CFIndex j=0; j < ABMultiValueGetCount(multi); j++) {
iimage=nil;
phone=nil;
phone = (__bridge NSString*)ABMultiValueCopyValueAtIndex(multi, j);
//if number matches
if([phone isEqualToString:searchnumber])
{
NSLog(#"equlas%#",searchnumber);
//if person has image store it
if (ABPersonHasImageData(ref)) {
CFDataRef imageData=ABPersonCopyImageDataWithFormat(ref, kABPersonImageFormatThumbnail);
iimage = [UIImage imageWithData:(__bridge NSData *)imageData];
}else{
//default image
iimage=[UIImage imageNamed:#"icon"];
}
//set image and name
userimage.image=iimage;
lblname.text=firstName;
return;
}
}
}
}

NSScreen leaking under GarbageCollection, Is this a bug

I've been trying to debug memory leaks in an objective-c program for the last couple of days and was playing around with some very basic sample code to test some ideas and came across something that seems to be a bug to me but wanted to get some opinions from those with more knowledge when it comes to developing in the Mac world.
I have the following bit of code:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRect desktopRect = NSZeroRect;
NSArray* screens = [[NSScreen screens] autorelease];
int x = 0;
for (x = 0; x < [screens count]; x++)
{
NSScreen *screen = [screens objectAtIndex:x];
}
[pool drain];
This code lives inside a method that I am calling from a while loop that continues until I kill the process. (Remember this is just a simple test.)
When I run this loop and watch allocations in Instruments things work perfectly fine when I am not implementing Garbage Collection. My overall number of allocations stays constant and everything with the NSScreens are getting cleaned up and released.
As soon as I enable Garbage Collection, the call to [NSScreen screens] starts leaking core graphics objects like mad by never releasing them.
I have seen in other forums where people a few years back talked about Core Graphics being very leaky under Garbage Collection. I'm wondering if that is the case here as well.
Any thoughts from the community?
Ok, I'm going to go out on a limb here and say that yes it is a bug on Apples part though I did find a solution using some Toll-Free-Bridging magic. I modified the code to be:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRect desktopRect = NSZeroRect;
CFArrayRef screens = CFMakeCollectable((CFArrayRef)[NSScreen screens]);
int x = 0;
for (x = 0; x < [screens count]; x++)
{
NSScreen *screen = (NSScreen*)CFArrayGetValueAtIndex(screens,x);
}
[pool drain];
By calling CFMakeCollectable on the toll-free-bridged array, it allowed the background core graphics objects to be properly cleaned up when using garbage collection.
This definitely makes me think that Apple needs to do some more work with Garbage Collection and Cocoa objects that wrap Core Graphics.

Resources