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;
}
}
}
}
Related
I'm trying to create a basic quiz app where the questions will not repeat. I've looked at several examples and believe I should be storing the questions in an array and then removing one from the array each time its used. I've tried the following code.
- (void)viewDidLoad
{
//The array of questions
NSMutableArray *questionArray = [[NSMutableArray alloc] initWithObjects:
[NSMutableArray arrayWithObjects:#"First Question",#"Answer A", nil],
[NSMutableArray arrayWithObjects:#"Second Quesiton",#"AnswerA",#"AnswerB", nil],
nil];
//remove used question from array
for (int i = questionArray.count; i>=0; --i) {
_questions = [questionArray objectAtIndex:arc4random() % questionArray.count];
[questionArray exchangeObjectAtIndex:i withObjectAtIndex:_questions];
}
//use array object
self.lblQuestion.text = [_questions objectAtIndex:0];
[self.btnA setTitle:[_questions objectAtIndex:1] forState:UIControlStateNormal];
[super viewDidLoad];
}
I'm getting the following warning:
Incompatible pointer to integer conversion sending NSMutableArray*_strong to parameter of type 'NSUInteger'
I take it this means I shouldn't be using another array to store the random question as I can't use this to remove the question from the array. However I don't know how else to do this?
Am I completely misunderstanding how I should go about this?
Since your goal here is to get non-repeating questions...
I believe that instead of removing the question you have already used, you should SHUFFLE your array at the beginning and then loop through the array one index at a time using a simple counter.
I hope you can find this piece of code helpful -- give it a shot:
-(NSMutableArray *)shuffleArray:(NSMutableArray *)anArray
NSUInteger count = [anArray count];
for (NSUInteger i = 0; i < count; ++i)
{
int nElements = count - i;
int n = (arc4random() % nElements) + i;
[anArray exchangeObjectAtIndex:i withObjectAtIndex:n];
}
return anArray;
}
-(void)viewDidLoad
{
//The array of questions
NSMutableArray *questionArray = [[NSMutableArray alloc] initWithObjects:
[NSMutableArray arrayWithObjects:#"First Question",#"Answer A", nil],
[NSMutableArray arrayWithObjects:#"Second Quesiton",#"AnswerA",#"AnswerB", nil],
nil];
//Shuffle the question array -- Now all indexes are shuffled and Random
questionArray = [self shuffleArray:questionArray];
//Every time you want to move to the next question, all you have to do is connect a button to the nextIndex action and let it do all the work!
//Use the nextIndex method to initialise -- we call it manually the first time so things would get going and something is displayed -- you can remove the line below if you want it to initialise on first button click! Your call the shots sir!
[self nextIndex];
[super viewDidLoad];
}
//Edit -- This method shows how to change question array index using a method
int currentIndex = 0;
-(IBAction)nextIndex
{
if ( currentIndex == [questionArray count] )
{
currentIndex = 0; //Resets the var when getting to the final Index
//The above line will result in a question loop -- meaning if you arrive at the last question, the next question will be the first! Pacman mode!
//If you want to stop at the last question just change the above line to return; and you're all set!
}
//Set _questions object to the current Index Array element
_questions = [questionArray objectAtIndex:currentIndex];
//Increment currentIndex for next use
currentIndex++;
//use the array object to set your objects' values
self.lblQuestion.text = [_questions objectAtIndex:0];
[self.btnA setTitle:[_questions objectAtIndex:1] forState:UIControlStateNormal];
}
You will end up having totally different questions that are shuffled every time.
I hope you find this helpful.
I have 2 arrays. One is a collection of buttons. The other one should be an array of dictionaries. I am logging the length/size/count of object in the arrays in the console using [arrayListName count]:
2012-07-19 19:56:59.001 ABC[3224:707] lastest_badge_outlet_collection count: 4
2012-07-19 19:56:59.007 ABC[3224:707] badges_array count: 1
ok so when running this loop I want to populate the images with the key value 'name' from each of the dictionaries in existence in the array (that is badges_array). At the moment I have dictionary stored in that array (which is fine). However when I run this through the loop it always populates the third image along
for(int i = 0; i < [lastest_badge_outlet_collection count]; i++){
UIButton *button = [lastest_badge_outlet_collection objectAtIndex:i];
if(i < [badges_array count]){
NSDictionary *badge_d = [badges_array objectAtIndex:i];
NSString *badge_d_image_string = [badge_d objectForKey:#"image"];
UIImage *badge_d_image = [UIImage imageNamed: badge_d_image_string];
[[button imageView] setImage:badge_d_image];
[[button imageView] setContentMode: UIViewContentModeScaleAspectFit];
[button setAlpha:1.0f];
} else {
[button setAlpha:0.5f];
}
}
Theoretically it should be populating the first image. Why is it doing this? How does it decide which order the items are in the outlet collection for example...
Mind boggled.
I tried rewiring them to the collection 1 by 1 by wiring them up in order with no success....
Here is a screenshot.
Thanks!
I don't think there is a way to predict the order of IBOutletCollection.
I guess what you need to do is sort the collection before use it.
You can set tag property for each button and sort them by those number.
Check this answer for more detail.
I want to be able to add a text comment to the metadata of a JPEG and be able to read it back from within an iphone app.
I thought this would be fairly simple as ios4 contains support for EXIF info. So I added metadata using a Windows tool called used AnalogExif and read it back from my app using:
NSData *jpeg = UIImageJPEGRepresentation(myUIImage,1.0);
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)jpeg, NULL);
NSDictionary *metadata = (NSDictionary *) CGImageSourceCopyPropertiesAtIndex(source,0,NULL);
NSMutableDictionary *metadataAsMutable = [[metadata mutableCopy]autorelease];
[metadata release];
NSMutableDictionary *EXIFDictionary = [[[metadataAsMutable objectForKey:(NSString *)kCGImagePropertyExifDictionary]
And that works...to a point :)
What I get back in the metadata dictionary is something like:
(gdb) po metadata
{
ColorModel = RGB;
Depth = 8;
Orientation = 1;
PixelHeight = 390;
PixelWidth = 380;
"{Exif}" = {
ColorSpace = 1;
PixelXDimension = 380;
PixelYDimension = 390;
};
"{JFIF}" = {
DensityUnit = 0;
JFIFVersion = (
1,
1
);
XDensity = 1;
YDensity = 1;
};
"{TIFF}" = {
Orientation = 1;
};
}
But thats all I can get! I've edited the JPEG file with every EXIF editor I can find (mostly PC ones I should say) and although they all say I have added JPEG comments and EXIF captions and keywords, none of that info seems to be available from the Apple SDK in my app.
Has anyone managed to set a text field in the metadata of a jpeg and manage to read it back from an iphone app?
I didn't want to use a third party library if at all possible
many thanks in advance
You're correct in thinking that iOS does support more metadata than what you're seeing. You probably lost the data when you created a UIImage and then converted it back to JPEG. Try NSData *jpeg = [NSData dataWithContentsOfFile:#"foo.jpg"] and you should see the EXIF.
I'm trying to compare two strings
NSString strOne = #"Cat, Dog, Cow";
NSString strTwo = #"Cow";
How do I determine if strOne contains strTwo
Try using rangeOfString:
NSRange result = [strOne rangeOfString:strTwo];
From the documentation:
Returns an NSRange structure giving the location and length in the receiver of the first occurrence of aString. Returns {NSNotFound, 0} if aString is not found or is empty (#"").
For anyone needing the code to check is a string exists within a string, here's my code thanks to fbrereto. This example checks to see if any string contained in an array of strings (stringArray) can be found within a string (myString):
int count = [stringArray count];
for (NSUInteger x = 0; x < count; ++x) {
NSRange range = [self.myString rangeOfString:[stringArray objectAtIndex:x]];
if (range.length > 0) {
// A match has been found
NSLog(#"string match: %#",[stringArray objectAtIndex:x]);
}
}
I believe this is the correct syntax for checking if the range exists (correcting response from Kendall):
range.location != NSNotFound
Gradually straying off topic, but I always explode my strings, which would mean just exploding it using your search string as a key and you can use the array count to see how many instances you have.
Just incase anyone is coming from a code language that uses "explode" to blow a string up into an array like me, I found writing my own explode function tremendously helpful, those not using "explode" are missing out:
- (NSMutableArray *) explodeString : (NSString *)myString key:(NSString*) myKey
{
NSMutableArray *myArray = [[NSMutableArray alloc] init];
NSRange nextBreak = [myString rangeOfString:myKey];
while(nextBreak.location != NSNotFound)
{
[myArray addObject: [myString substringToIndex:nextBreak.location]];
myString = [myString substringFromIndex:nextBreak.location + nextBreak.length];
nextBreak = [myString rangeOfString:myKey];
}
if(myString.length > 0)
[myArray addObject:myString];
return myArray;
}
works like this:
[self explodeString: #"John Smith|Age: 37|Account Balance: $75.00" key:#"|"];
which will return this array:
[#"John Smith", #"Age: 37", #"Account Balance: $75.00"];
This lets you quickly pull out a specific value in a tight space, Like if you have a client and you want to know how much money he has:
[[self explodeString: clientData key: pipe] objectAtIndex: 1];
or if you wanted specifically the dollar amount as a float:
[[[self explodeString: [[self explodeString: clientData key: pipe] objectAtIndex: 1] key: #": "] objectAtIndex: 2] floatValue];
anyway I find arrays way easier to work with and more flexible, so this is very helpful to me. Additionally with a little effort you could make an "explodable string" data type for your private library that lets you treat it like a string or return an index value based on the key
ExplodableString *myExplodableString;
myExplodableString.string = #"This is an explodable|string";
NSString *secondValue = [myExplodableString useKey: #"|" toGetValue: index];
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.