objective-c How to cache images from facebook using SDWebImage? - objective-c

Im new in iOS programming so i need some help.
I have a TableViewController with a property NSArray, where is stored Facebook User's friends info: uid, square_pic and name. I use to load their profile photos using FBProfilePictureView, by uid.
My problem: When user scroll the table pictures from cells take a lot of time to reload. I want to cache this photos using SDWebImage.
Thank's a lot.

I am not familiar to SDWebImage. Their readme mentions ability to cache, so you might want to figure it out on your own.
However, there is a really nice class called NSCache that you can implement in some of your managers or view controllers. Also, this post by Mattt Thompson covers it in great details.
It functions as a regular NSDictionary in sense that you can set object for keys and retrieve them. e.g:
//setting
[cache setObject:image forKey:#"yourImageURL"]
//accessing
UIImage *image = [cache objectForKey:#"yourImageURL"];
if (image == nil) {
// request it
}
But it also contains some awesome staff for setting values for objects which will serve as a hint which objects have to be removed in case of low memory.
Hope this helps to answer your question.
Cheers!

Related

Is It Possible To Customise CNContactPickerViewController?

I'm opening a CNContactPickerViewController for use in an application, but I want to alter the way it presents to suit my apps needs, preferably without rolling my own and doing a lot of re-inventing of the wheel. This is how I am opening it using Objective-C ....
self.contactPicker = [[CNContactPickerViewController alloc] init];
self.contactPicker.delegate = self;
//Only enable contacts to be selected that have atleast one email address
NSArray *propertyKeys = #[CNContactGivenNameKey, CNContactFamilyNameKey, CNContactEmailAddressesKey];
NSPredicate *enablePredicate = [NSPredicate predicateWithFormat:#"emailAddresses.#count != 0"];
self.contactPicker.displayedPropertyKeys = propertyKeys;
self.contactPicker.predicateForEnablingContact = enablePredicate;
[self presentViewController:self.contactPicker animated:YES completion:nil];
When it opens it currently looks like this:
However due to a bug in the SDK the search for people on this kind of view doesn't work, as you can not select from the search results. I'm going to file a bug for this but in the mean time firstly I want to hide the Search Bar. I found some old questions on removing the SearchBar but they related to the ABPeoplePickerNavigationController and are not relevant to CNContacts.
I also don't wish to use Groups and if I could remove that button and move the Cancel button over to the left that would be great, and would make the selection interface in my app much cleaner looking. This is how I would like it to look:
Could anyone tell me if this is possible and maybe point me in the right direction? I have the delegate method to receive the contacts array after selection, my problem is the way it looks in the app.
Thanks in advance!
Plasma
The real answer is the one you don't want to hear:
No, you can't modify the UI that Apple presents (at least in a meaningful way). You might be able to modify the tint color and other minor details, but you can't change whatever you like. If there's a bug in the search selector, you certainly can't fix that unfortunately. I'd suggest that just hiding the search bar isn't a great option, since for large contact lists, search is usually the primary way users will navigate to contacts.
Side note - a lot of Apple's framework view controllers are implemented
as a special sort of 'remote view controller'. The view controller
doesn't actually run as part of your app, but in the sandbox of the
parent application. This prevents any sort of trickery like traversing
and modifying the UI hierarchy of these presented controllers. I
wouldn't be surprised if that is the case here.
I would suggest that recreating the contact selection view isn't too hard, and gives you total flexibility in terms of customisation. I've done it myself, and there weren't any major hurdles to cross. Even if you're new to iOS, it would be a great learning exercise. For a good solution, you probably want to fetch all of the contacts on a background thread and display a loading spinner, since large contact databases could take a little while to fetch. (Even better, prefetch the contacts on the previous view, and only display a loading spinner if that fetch hasn't finished).
If you don't feel like doing that, I've seen a few contact selection frameworks around the place on GitHub. I'm not sure what the quality is like, but at the very least, these might provide a great starting point.
You can get an array of all contacts, and then display and work with it as you like:
- (NSMutableArray<CNContact *> *)allContacts {
NSMutableArray <CNContact *> *result = [NSMutableArray array];
NSError *error = nil;
NSArray *keysToFetch = #[CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactImageDataKey,
[CNContactFormatter descriptorForRequiredKeysForStyle:CNContactFormatterStyleFullName]];
CNContactStore *contactStore = [[CNContactStore alloc] init];
NSArray <CNContainer *> *allContainers = [contactStore containersMatchingPredicate:nil error:&error];
for (CNContainer *container in allContainers) {
NSPredicate *predicate = [CNContact predicateForContactsInContainerWithIdentifier:container.identifier];
NSArray *fetchedContacts = [contactStore unifiedContactsMatchingPredicate:predicate keysToFetch:keysToFetch error:&error];
[result addObjectsFromArray:fetchedContacts];
}
return result;}

How to add the iOS "Open In..." feature to an app

I would like to know how to present the "Open In..." Action Sheet (iPhone) / Popover (iPad) from my app, preferably an IBAction
I would hope that it'd be similar to declaring a file type then creating the view and opening the app selected by the user, but I know it is more complicated then that.
I realize that a similar question has been asked on StackOverflow, but I cannot make sense of the answer that was accepted: How to use "open in..." feature to iOS app?, and I have found some Apple Documentation on Document Interaction Programming. But, I can't really make sense of these.
Create a UIDocumentInteractionController by using the interactionControllerWithURL: class method (pass the URL of the file you want to open in another app).
Then call either presentOpenInMenuFromRect:inView:animated: or presentOpenInMenuFromBarButtonItem:animated:. The controller takes care of presenting the popover with available apps for that file type and opening the selected app.
If you want to know when the menu was dismissed and which app was selected, you need to implement the UIDocumentInteractionControllerDelegate protocol.
omz makes some good points on how to do that in his answer, however this procedure is much easier with the introduction of new APIs in iOS 6. Here's a simple and efficient way to show the UIActionSheet Open-In-Menu in iOS 6 and up:
NSArray *dataToShare = #[contentData]; //Or whatever data you want to share - does not need to be an NSArray
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:dataToShare applicationActivities:nil];
[self presentViewController:activityViewController animated:YES completion:nil];
Also, if your app is compatible with versions of iOS lower than 6.0 you may want to check if the Share Service exists:
if ([UIActivityViewController class])
Once you present the sheet, iOS will automatically handle the rest for you. It will display a beautiful uiactionsheet with icons showing each app or service the user can open / share your data with:
Note that depending on the contents of the data, iOS will show different services in the Share Sheet
EDIT: The method above shares the file content, but not the file itself. Refer to omz's answer for more on that.
I've personally never had to do this, but your answer can most certainly be found in this Apple Documentation: http://developer.apple.com/library/ios/#documentation/FileManagement/Conceptual/DocumentInteraction_TopicsForIOS/Articles/PreviewingandOpeningItems.html#//apple_ref/doc/uid/TP40010410-SW1.

iOS - Loading an image from a web server in Objective C

At the moment, I have a goal of writing an application that contains a UIImageView. Upon loading or pressing a button, an image from a web server will load into the view.
What is the simplest way to do this? I'm assuming using the API described here? https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html
In the mean time, I will continue to try to get this working on my own. Any advice would be appreciated, especially if you have written code like this before.
Yes, this can be done by making a request through an NSURLConnection.
You might be interested in checking out SDWebImage. This library includes a category that adds a method to UIImageView that makes asynchronously loading an image from a remote URL as simple as this:
[self.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:#"placeholder.png"]];

Variables in different navigation stack

Sorry if my question does not match the title, but i think it does:
I have an app with a navigation controller and 3 views. It's an app where you connect to a server and talk with friends.
The thing is, my rootViewController, the login screen, calls the second view witch is the friends list. clicking in a friend on the list takes you to the third view, the chat screen itself.
I wanted to, when the user logs in (rootview), to store the user name used in a variable, so i could use it on the third view, the chat screen, so when he sends a message it can have his name on it, and while retrieving info from server, i can use his name as a parameter too.
By the way, is SQLite the best way to save messages and users? I am afraid of Core Data =/
To keep things loosely coupled I would consider just passing along the userName when instantiating each UIViewController sub class. (Makes unit testing easier as well)
e.g.
// LoginViewController -> user logs in
FriendsViewController *friendsViewController = [[FriendsViewController alloc] initWithUserName:userName];
[self.navigationController pushViewController:friendsViewController];
[friendsViewController release]; friendsViewController = nil;
// FriendsViewController -> user selects a friend
ChatViewController *chatViewController = [[ChatViewController alloc] initWithUserName:userName];
[self.navigationController pushViewController:chatViewController];
[chatViewController release]; chatViewController = nil;
Don't be afraid of core data there are plenty of excellent books out there.
Core data is not that bad. This is the guide I used to get started with Core Data. Once you wrap your head around how everything works it really isn't that bad.
If you wanted to you could use SQLite, but it's a lot of code. Core Data is much simpler to use.

Can anyone help out an Objective C novice?

I feel i am totally out of my depth here, im very new to objective c but have been asked to design an iphone app as part of my uni course. I designed a sinple quiz before, but I was hoping to design a more advanced quiz game with 3 levels (each level will have a different quiz).
I dont know how to use the UIViews and I have tried a tutorial online to help me code a navigation controller. It allows gives me 3 options to go into subview 1, 2 or 3. All the subviews have the same screen though, with one label and a button.
I have 3 classes so far, RootViewController, BasicNavigationAppDelegate and SubViewOneController.
I really dont understand the code at all, im familiar with Java but this objective c is nothing like it. Could someone maybe take a minute to help out a person in distress and explain if i am doing this right by using the navigation controller to display my levels? When i check the xib interface files i dont see the button or label, or dont know where to add the quiz interface objects!! I really am confused by all this. Could anyone help?
You should search google for sample source code, and see how some of the views can be handled. There are many ways you can handle a view, whether its by a UINavigationController, UITabBarController, etc. If you are new to Objective-C, then your not really going to get an answer to this question that will instruct you on what exactly to do.
Interface Builder + View Controllers
Here's a good one for you: View Controllers Programming Guide
(Apple's) View Controller Reference Guide
Some Code Samples
Getting Started Sample Code
I recommend Head First iPhone Development: A Learner's Guide to Creating Objective-C Applications for the iPhone. Within a few chapters you'll know everything you need to build this app and you'll actually understand what you're doing.
(I don't know the authors or the publisher, I just think it's a great book for quickly getting up to speed.)
for a 3 level quiz, UINavigationController is definitely an option.
if you need to find out how to use a class, in xcode, type its name, then press -alt- and double click the class name, this will bring up a short description, with two icons, one will take you to the header file, and the other to the documentation.
to add elements to the nib/xib files, you will need to open the library window, where you will find labels, buttons etc. to use a button, you will need to define an action in your header file, and hook it up in IB, to be able to interact with UIElements in your code, you want to set up outlets in the header file, and hook them up in IB.
something you need to decide on, is how you are going to present the questions, and will also depend if the answer will be true/false, multiple choice, or text entry.
if you arent familiar with obj-c and xcode, it is probably worth picking up an ebook from someone like http://www.pragprog.com. they have an iPhone one up there by Bill Dudney which is quite good(i believe he now works for apple.)
for the standard slide out transition you could use this.
//you would probably want to call this something like level1NavBarItemWasPushed: instead
- (IBAction)lvl1pushNavBarItem:(id)sender {
//create instance of AnswersViewController class.
AnswersViewController *level1AnswersVC= [[Level1AnswersViewController alloc] init];
//pass it some kind of identifier so it can tell which quiz/question it is dealing with and pull in the answers, so that you can reuse the view
[level1AnswersVC setAnswersObject:<<insert object dictionary here>>];
//push the view controller onto the navigationController's view stack
[self.navigationController pushViewController:level1AnswersVC animated:TRUE];
//pushing it onto the view stack has given it +1 retain, so we can now release it without worrying about it disappearing prematurely.
[level1AnswersVC release];
}
for the page flip transition you could use this.
- (IBAction)lvl1pushNavBarItem:(id)sender {
//create instance of AnswersViewController class.
AnswersViewController *level1AnswersVC= [[Level1AnswersViewController alloc] init];
//pass it some kind of identifier so it can tell which quiz/question it is dealing with and pull in the answers, so that you can reuse the view
[level1AnswersVC setAnswersObject:<<insert object dictionary here>>];
//set the current viewController as the delegate, so that it can call back to us when its done
level1AnswersVC.delegate = self;
//set the modal transition style
level1AnswersVC.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
//show answers as modal view, which has been setup to use the page flip transition.
[self presentModalViewController:level1AnswersVC animated:YES];
//pushing it onto the view stack has given it +1 retain, so we can now release it without worrying about it disappearing prematurely.
[level1AnswersVC release];
}