Limit Social Sharing Options and Set Custom Message for Each Service - objective-c

I am about to implement a share button calling the default modal sharing activities view.
Here's what I got so far.
NSString *textToShare = [NSString stringWithFormat:#"Looking forward to meet you at %#",[eventItemObject eventName]];;
NSURL *url = [eventItemObject eventWebsiteURL];
NSArray *activityItems = [[NSArray alloc] initWithObjects:textToShare,url,nil];
UIActivity *activity = [[UIActivity alloc] init];
NSArray *applicationActivities = [[NSArray alloc] initWithObjects:activity, nil];
UIActivityViewController *activityVC =
[[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:applicationActivities];
[self presentViewController:activityVC animated:YES completion:nil];
This is called when I press the sharing button.
Challenge:
Limit the sharing option to e.g. Facebook, Twitter, Mail (It now also shows Copy to Clipboard and Weibo)
Assign custom sharing messages/strings for each sharing method. (now the textToShare string is used for all services)
After some research I think this can be done with the new SLComposeViewController (in iOS6), but I am not sure where/how to call it correctly. Any practical advice or example is appreciated!

You can specify which activities not to show be using the activityViewController's setExcludedActivityTypes:. Example:
[activityVC setExcludedActivityTypes:[NSArray arrayWithObjects:
UIActivityTypeMessage,UIActivityTypeCopyToPasteboard,
UIActivityTypeAssignToContact,UIActivityTypePostToWeibo,
UIActivityTypePrint,UIActivityTypeSaveToCameraRoll,
nil]];
As far as sending specific content to different activities goes, I've spent the last day or so trying to figure out how to do that. I'll update this post to include this info if/when I figure it out.

Related

Write NSDictionary to ONLINE .plist. Is it possible?

I'm writing an app for instant messaging aaand I'm stuck.
I am able to read data (dictionary) from plist that's on my dropbox, but I can't modify it from my app, what is a thing I actually want to achieve.
Here is how I read the online .plist file:
#Implementation
NSDictionary *wholePlist;
-(void)viewDidLoad
{
wholePlist = [[NSDictionary alloc]initWithContentsOfURL: [NSURL URLWithString:[NSString stringWithFormat:#"https://dl.dropboxusercontent.com/s/cfpree9see19t00/users.plist"]]];
self.allUsers = [wholePlist objectForKey:#"allUsers"];
} //self.allUsers is NSDictionary, also.
And this is how I am trying to save it if I change it
- (IBAction)registerButtonPressed:(UIButton *)sender {
NSString *username = self.usernameTextField.text;
NSString *password = self.setPassTextField.text;
NSMutableArray *myContacts = [[NSMutableArray alloc]init];
NSMutableArray *inbox = [[NSMutableArray alloc]init];
NSDictionary *user = [[NSDictionary alloc]initWithObjects:#[username, password, myContacts, inbox] forKeys:#[#"username",#"pass",#"myContacts",#"inbox"]];
if ([user isEqualToDictionary:[self.allUsers objectForKey:username]]) {
[[[UIAlertView alloc]initWithTitle:#"Registration error" message:#"Username already taken. Please, choose another username." delegate:self cancelButtonTitle:nil otherButtonTitles:#"OK", nil]show];
} else {
NSURL *plistURL = [NSURL URLWithString:[NSString stringWithFormat:#"https://dl.dropboxusercontent.com/s/cfpree9see19t00/users.plist"]];
[self.allUsers setValue:user forKey:username];
[self.allUsers writeToURL:plistURL atomically:YES];
}
}
If I do it locally/offline (in some folder inside my Mac or app directory) using writeToFile: it works. When I use writeToURL: it doesn't work.
My questions are:
Is this even possible, what am I trying to achieve?
Is it possible with any other storage client?
If it's possible with some other storage client, please give me source link on how to OR explain how to.
Thanks!
Instant messaging applications are almost always best done using sockets. I'd HIGHLY recommend against using a file on a server to read and write from. While it's possible, you're asking for a world of pain and slugish-ness.
So to answer your questions in a striaght forward manner:
Yes... Don't do it.
Yes. of course you can use CloudKit either the DB or file upload part. Again, I recommend against this method because it's slow and has high overhead on the network.
I highly recommend reading up on sockets: http://en.wikipedia.org/wiki/Network_socket to better understand this approach. I have a chat socket written in C++. However it does a bit more than what you may need: https://github.com/theMonster/ModularServer. Also, there's a very popular chat server example for node.js here: http://socket.io/get-started/chat/
Let me know if you have any questions.

Good Design for Contact Apps - Custom Table Cell Layout

Note: After reading, please edit title if not appropriate.
I'm just amateur in iOS. I practicing the objective-C with self-task and I'm trying to create a Contact Apps without any backend.
Problem:
In my app, I would like to display name and image in a cell. How can I achieve this?. I've already tried by adding to the sub view, the label(For Name) and image view (For Image) to a cell. But, it gives more conditional check for each of the different contact types. Like...
//In cellForRowAtIndexPath,
UILabel *lblForCell=[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 30)];
lblForCell.text=[arrForMyContacts objectAtIndex:indexPath.row];
[tblCellForContactTable.contentView addSubview:lblForCell];
if([lblForCell.text isEqual:#"Mom"]){
UIImageView *imgForContact=[[UIImageView alloc] initWithFrame:CGRectMake(200, 10, 60, 7)];
imgForContact.image=[UIImage imageNamed:#"Mom.png"];
[tblCellForContactTable.contentView addSubview: imgForContact];
}
//likewise condition increased for dad, bro etc...- bad design, Correct?
So tell me its there any other way to decrease condition.
There are several ways to do. First create an array of Dictionary. Something like this
NSMutableArray *contacts = [[NSMutableArray alloc] init];
NSDictionary *mom = [NSDictionary dictionaryWithObjectsAndKeys:#"MOM", #"Name",
#"mom.png", #"imageName",
nil];
NSDictionary *dad = [NSDictionary dictionaryWithObjectsAndKeys:#"DAD", #"Name",
#"dad.png", #"imageName",
nil];
NSDictionary *son = [NSDictionary dictionaryWithObjectsAndKeys:#"SON", #"Name",
#"son.png", #"imageName",
nil];
[contacts addObjectsFromArray:#[mom, dad, son]];
Second create a custom UIView class where you can render this dictionary with init method something like this
-(id)initWithContactInfo:(NSDictionary *)contactInfo;
Third at the tableView
//In cellForRowAtIndexPath,
NSDictionary *contact = [contacts objectAtIndex:indexpath.row];
MYCustomView *contactCell = [[MYCustomView alloc] initWithContactInfo:contact];
[cell.contentView addSubView:contactCell];
Making a custom View gives you flexibility of customizing your view for particular cell.
I hope it helps . Best of luck

How to add NSArray in a video with AVMutableMetadataItem?

I am trying to save video with custom NSArray metadata relevant for my app and trying to retrieve it when the user selects that video from the library.
I'm using the AVAssetExportSession function to add metadata.
I used the sample code AVMovieExporter, and I tried to change locationMetadata.value
http://developer.apple.com/library/ios/#samplecode/AVMovieExporter/Introduction/Intro.html#//apple_ref/doc/uid/DTS40011364
AVMutableMetadataItem *locationMetadata = [[AVMutableMetadataItem alloc] init];
locationMetadata.key = AVMetadataCommonKeyLocation;
locationMetadata.keySpace = AVMetadataKeySpaceCommon;
locationMetadata.locale = self.locale;
//locationMetadata.value = [NSString stringWithFormat:#"%+08.4lf%+09.4lf", self.location.coordinate.latitude, self.location.coordinate.longitude];
locationMetadata.value = [[NSArray alloc] initWithObjects: #"abc", #123,nil];
If I use value as a NSString there is no problem, but if I use a NSArray, it doesn't save the metadata.
Where is the problem?
Apple's documentation states:
NSString *const AVMetadataCommonKeyLocation;
I understand that to say the value must be a string, and cannot be an array.

Create multiple UILocalNotifications

I want to create a new UILocalNotification every time I enter a certain method. I would assume this would have to be done by reading from an array or something along this line but I cannot figure it out. How do I do such a thing dynamically without hardcoding something like the following:
-(void) createNotification
{
UILocalNotification *notification1;
}
Now I would like to be able to create notification2, notification3, etc etc each time I enter createNotification. For the specific reason that then I can cancel the appropriate notification without cancelling them all.
The following is what I have attempted, perhaps Im way off... maybe not. Either way if someone could provide some input, would be appreciated. Thanks!
-(void) AddNewNotification
{
UILocalNotification *newNotification = [[UILocalNotification alloc] init];
//[notificationArray addObject:newNotification withKey:#"notificationN"];
notificationArray= [[NSMutableArray alloc] init];
[notificationArray addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:newNotification,#"theNotification",nil]];
}
You are almost there: using an array is certainly the right thing to do! The only problem is that you keep creating a new instance of the array every time you go through your AddNewNotification method. You should make notificationArray an instance variable, and move its initialization code notificationArray= [[NSMutableArray alloc] init]; to the designated initializer of the class where notificationArray is declared.
If you would like to give each notification that you insert an individual key by which you can find it later, use NSMutableDictionary instead of NSMutableArray. Re-write the AddNewNotification method as follows:
-(void) addNewNotificationWithKey:(NSString*)key {
UILocalNotification *newNotification = [[UILocalNotification alloc] init];
[notificationDict setObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:newNotification,#"theNotification",nil]
forKey:key];
}
When you call the addNewNotificationWithKey: method, you'd be able to provide a key for the newly added notification, for example
[self addNewNotificationWithKey:#"notification1"];
[self addNewNotificationWithKey:#"notification2"];
and so on.

NSURLConnection delegate

REVISED...
The crux of the app is communicating with a database server. Responses from the server to the app are all in XML. There are several screens. Example, screen 1 lists the user's information, screen 2 lists the user's past trades, allows new trades, and so on.
Here is some code from my AppDelegate:
StartViewController *svc = [[StartViewController alloc] init];
TradeViewController *tvc = [[TradeViewController alloc] init];
CashViewController *cvc = [[CashViewController alloc] init];
ComViewController *covc = [[ComViewController alloc] init];
PrefsViewController *pvc = [[PrefsViewController alloc] init];
NSMutableArray *tabBarViewControllers = [[NSMutableArray alloc] initWithCapacity:5];
UITabBarController *tabBarController = [[UITabBarController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:svc];
[tabBarViewControllers addObject:navigationController];
navigationController = nil;
navigationController = [[UINavigationController alloc] initWithRootViewController:tvc];
[tabBarViewControllers addObject:navigationController];
navigationController = nil;
navigationController = [[UINavigationController alloc] initWithRootViewController:cvc];
[tabBarViewControllers addObject:navigationController];
navigationController = nil;
navigationController = [[UINavigationController alloc] initWithRootViewController:covc];
[tabBarViewControllers addObject:navigationController];
navigationController = nil;
navigationController = [[UINavigationController alloc] initWithRootViewController:pvc];
[tabBarViewControllers addObject:navigationController];
navigationController = nil;
[tabBarController setViewControllers:tabBarViewControllers];
[[self window] setRootViewController:tabBarController];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
Trying to stick with the MVC style, I have a singleton class which does all of the "processing".
Now an example on how I run into a wall… the user can change their email address on screen 5. Enter new email address into text field and click the save button. The button then calls a method from the singleton class which sends the new email address to the server and (via the URL) and receives a XML response confirming the change.
Here are my problems:
1. I start the spinner from the view controller before I make the singleton class method call - but not knowing when the app to server send/receive is finished, how do I make the spinner stop at the right time? I can't of it from the singleton class, I tried that. From what I know, it has to be from within the VC or is there a way to change VC output from my singleton class?
The singleton class NSURLConnection is handling ALL of my communication. Everything from a simple, email change all the way to updating transaction tables. This just seems wrong to me and makes it very difficult to keep track on who is calling what. Again, I am going by my interpretation of MVC. I think it would be much easier to have a NSURLConnection for every VC and do some processing in those classes. However that would not be MVC(ish).
I have close to a 100 variables, arrays, etc… in my singleton class which I use to assign values to all my VC. This also seems wrong to me but I can't think of any other way.
how can I distinguish in the NSURLConnection delegate
(connectionDidFinishLoading) which URL call is being made?
Each of the delegate methods (such as -connectionDidFinishLoading:) has a connection parameter that tells you which connection sent the message. A given connection can only load one URL at a time, so there's a one to one correspondence between URLs and connections.
How can I tell outside of "connectionDidFinishLoading" when the download is completed?
That method tells you when the connection is finished. It's up to you to store that information somewhere where it's useful to your app.
Update: Based on what you've added, your "processing" class is your app's model. The rest of the app shouldn't care that each transaction involves a message to the server -- that's the model's business alone. Also, there's no reason that the model has to be a single object (let alone a singleton) -- it can be a group of objects that work together.
So, you might have a class (let's call it Processor) that represents the application's interface to the model (some might even call this a "model controller"). An instance of Processor might create a local database for storing the current local state of the app.You might also have a Transaction class that represents a single transaction with the server. A transaction could create a request, send it to the server, get the response, update the database, and tell the Processor that the transaction is done. Or, maybe when some other part of the app (like one of your view controllers) asks the Processor to process a new transaction, the Processor passes the requesting object along to the transaction that it creates so that the transaction can update the requestor directly.
It's hard to say what the best plan for your app is without knowing where you're planning on taking it, but the usual guidelines hold:
break your problem into parts that are easier to solve
limit the scope of each class's responsibilities
if something seems to complicated, it probably is
Breaking your model up into several classes will make it easier to test, as well. You can imagine how easy it would be to write a set of unit tests for the Transaction class. The same goes for Processor -- if the server transaction stuff is in a different class, it's easier to test that the Processor is doing the right thing.
If you have multiple NSURLConnections for the same delegate, consider using a global (well, let's say rather an instance variable) NSMutableDictionary instance, in which you store the data depending on which NSURLConnection is being called. You can use, for example, the in-memory address of the connections converted to an NSString (something like
[NSString stringWithFormat:#"%p", connection]
should do the trick).
Also, in the connectionDidFinishLoading: and connection:didFailLoadWithError: methods, remove the keys corresponding to the NSURLConnections. Thus, you can tell it from 'outside' if a connection is finished: just check if it is in the dictionary or not.
If you're downloading any data over a network connection, I would suggest using ASIHttpRequest. This will allow you to download files asynchronously, meaning your interface doesn't freeze during the download process.
If you use ASIHttpRequest, you can also set the didFinishSelector. By doing this, you can control which method is called when a specific URL has finished loading.
Have a look at this:
NSURL *url = [NSURL URLWithString:#"http://allseeing-i.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
[request setDidFinishSelector:#selector(requestDone:)];
Then:
- (void)requestDone:(ASIHTTPRequest *)request
{
// Use when fetching text data
NSString *responseString = [request responseString];
// Use when fetching binary data
NSData *responseData = [request responseData];
// If you want, you can get the url of the request like this
NSURL *url = [request url];
}
As for the second part of your question, if the requestDone: method has not been called, you know the download has not completed.
If you want to do something more complicated with multiple downloads, ASIHttpRequest offers queue functionality too. Take a look here.
Hope this will help you.
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
NSString *urlString = [[[connection originalRequest] URL] absoluteString];
if ([urlString caseInsensitiveCompare:#"http://www.apple.com"] == NSOrderedSame) {
//Do Task#1
}
else if ([urlString caseInsensitiveCompare:#"http://www.google.com"] == NSOrderedSame)
{
//Do Task#2
}
}
I would recommend subclassing NSURLConnection. Simply add two properties: an NSInteger, tag, and a BOOL, isFinished. This way, you can #define tags for each different request and then identify them by tag in your delegate methods. In connectionDidFinishLoading, you can set the isFinished BOOL to YES, and then you can check in other methods if then connection is finished.
Here's my own NSURLConnection subclass, TTURLConnection:
TTURLConnection.h:
#import <Foundation/Foundation.h>
#interface TTURLConnection : NSURLConnection <NSURLConnectionDelegate>
#property (nonatomic) NSInteger tag;
#property (nonatomic) BOOL isLocked;
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:
(BOOL)startImmediately tag:(NSInteger)tagParam;
#end
TTURLConnection.m:
#import "TTURLConnection.h"
#implementation TTURLConnection
#synthesize tag;
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:
(BOOL)startImmediately tag:(NSInteger)tagParam {
self = [super initWithRequest:request delegate:delegate
startImmediately:startImmediately];
if(self) {
self.tag = tagParam;
}
return self;
}
#end