I'm using ShareKit 0.2.1 on Xcode 4.2 (iOS SDK 5) to share text on Twitter. It shares fine, but the modal view controller wont go away after successfully sharing on after clicking on the cancel button (see below):
And this is my code:
-(IBAction)shareOnTwitter:(id)sender{
// Item to share
NSString *text = #"Go away, modal view controller!";
[SHKTwitter shareText:text];
}
What am I doing wrong?
It is an iOS 5 issue. It's because ShareKit is using a method on UIViewController called parentViewController and according to the Apple docs you can no longer use this in iOS 5. Instead, you must use presentingViewController.
So to fix it in the ShareKit code, go into SHK.m, find the method with signature (void)hideCurrentViewControllerAnimated:(BOOL)animated, and replace it with:
- (void)hideCurrentViewControllerAnimated:(BOOL)animated
{
if (isDismissingView)
return;
if (currentView != nil)
{
// Dismiss the modal view
if ([currentView parentViewController] != nil)
{
self.isDismissingView = YES;
[[currentView parentViewController] dismissModalViewControllerAnimated:animated];
} else if ([currentView presentingViewController] != nil) {
self.isDismissingView = YES;
[[currentView presentingViewController] dismissModalViewControllerAnimated:animated];
} else
self.currentView = nil;
}
}
This works for me on iOS 5.
if (isDismissingView)
return;
if (currentView != nil)
{
// Dismiss the modal view
if ([currentView parentViewController] != nil)
{
self.isDismissingView = YES;
[[currentView parentViewController] dismissModalViewControllerAnimated:animated];
}
else {
//## ADD BELOW ##
self.isDismissingView = YES;
[currentView dismissModalViewControllerAnimated:animated];
self.currentView = nil;
}
}
else {
[[self getTopViewController].navigationController popViewControllerAnimated:YES];
}
This is the code I use in one of my apps.
It dismisses fine.
NSURL *url = [NSURL URLWithString:#"http://itunes.apple.com/us/app/packager/id459511278?l=nl&ls=1&mt=8"];
NSString *twittertext = [[NSString alloc] initWithFormat: #"Tweet Text"];
SHKItem *item = [SHKItem URL:url twittertext];
// Share the item
[SHKTwitter shareItem:item];
[twittertext release];
I have used the following code in my app (ARC disabled)
NSString *text = #"Go away, modal view controller!";
[SHKTwitter shareText:text];
I can confirm it dismisses fine.
You probably changed some code in SHKTwitterForm.m when attempting to make Sharekit ARC compatible. Which resulted in your bug
Related
So the backend is working, I can successfully create accounts and login. Now I want them to transition to the home screen so how I do I set so if the sigup/login is successful it transitions? This is my code:
- (IBAction)signUp:(UIButton *)sender {
NSString *name = _textUsername.text;
NSString *password = _textPassword.text;
NSString *email = [_textEmail.text lowercaseString];
//---------------------------------------------------------------------------------------------------------------------------------------------
if ([name length] == 0) { [ProgressHUD showError:#"Name must be set."]; return; }
if ([password length] == 0) { [ProgressHUD showError:#"Password must be set."]; return; }
if ([email length] == 0) { [ProgressHUD showError:#"Email must be set."]; return; }
//---------------------------------------------------------------------------------------------------------------------------------------------
[ProgressHUD show:#"Please wait..." Interaction:NO];
PFUser *user = [PFUser user];
user.username = name;
user.password = password;
user.email = email;
user[PF_USER_EMAILCOPY] = email;
user[PF_USER_FULLNAME] = name;
user[PF_USER_FULLNAME_LOWER] = [name lowercaseString];
[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (error == nil)
{
ParsePushUserAssign();
[ProgressHUD showSuccess:#"Succeed."];
[self dismissViewControllerAnimated:YES completion:nil];
}
else [ProgressHUD showError:error.userInfo[#"error"]];
}];
Also any idea why my text field doesn't automatically go to the next one? Pretty sure the code is right. Thanks.
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == _textUsername)
{
[textField resignFirstResponder];
[_textEmail becomeFirstResponder];
}
else if (textField == _textEmail)
{
[textField resignFirstResponder];
[_textPassword becomeFirstResponder];
}
else if (textField == _textPassword)
{
[textField becomeFirstResponder];
[_textBirthday becomeFirstResponder];
}
else if (textField == _textBirthday)
{
[self actionRegister];
}
return YES;
The way I arrange my parse.com apps is to have the main VC, the one that does the app's usual business for a logged-in user, be the storyboard's starting VC. It's first job in viewDidAppear, is to check that the PFUser currentUser exists (and is logged-in if your app requires it). If it isn't, then and only then, present the login/signup VC.
When login/signup dismisses as you have it in the posted code, viewWillAppear in your main VC fires again and detects the ready-to-run condition. It's action in that case is to carry on with initialization for a logged in user.
EDIT - For example, I have an app where the main VC is the starting VC in storyboard. It has a segue with identifier == #"GetUser" drawn from it to my equivalent of your signup/login VC.
Here's the (slightly simplified) viewDidAppear from my main VC.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// I require only a non-nil currentUser to run the app. Your check
// might be more elaborate...
PFUser *user = [PFUser currentUser];
if (user) {
// put up a "busy" UI. In my app, it's just a view with UIActivityIndicator
// update the user so we know its current
[user fetchInBackgroundWithBlock:^(PFObject *object, NSError *error) {
// remove the "busy" UI
[self startTheApp];
}];
} else {
[self performSegueWithIdentifier:#"GetUser" sender:self];
}
}
-(void)startTheApp {
// fetch data from parse.com and reload the table view that's the
// centerpiece of the UI for this VC.
}
The nice behavior here is when the login/signup succeeds, the currentUser is non-nil, so when the login/signup VC is dismissed, viewDidAppear as shown above is fired again because the main VC underneath is being revealed again. And on that second time through, the currentUser passes the starting condition and we go to startTheApp.
I am making a chat application, and when the person logs onto the chat successfully, the server replies with the people that are online at that moment. That string (the server sends a string) gets converted to a NSMutableArray, which is then stored into a NSMutableArray called tableData, which is the data source for a NSTableView. When the online people are stored into tableData, the NSLog output shows that tableData is filled. However, when that method is done, and the login view is closed, in the debugger tableData says 0 Objects, and the NSTableView doesn't fill, which it normally does. Here is are my methods (one calls another):
- (void)getPeople:(NSString *)outputMessage
{
NSArray *newTableData = [outputMessage componentsSeparatedByString:#";"];
self.tableData = [NSMutableArray arrayWithArray:newTableData];
//[self.tableData removeObjectAtIndex:0];;
NSLog(#"Data: %#", self.tableData);
[self.people reloadData];
}
- (void)accessGrantedWithOnlineUsers:(NSString *)users
{
NSLog(#"Access Granted");
self.isLoggedIn = YES;
[self.loginButton setTitle:#"Logout"];
[self getPeople:users];
}
Here is my method that opens and closes the login view:
- (IBAction)loginToChat:(id)sender {
NSLog(#"Called");
if (self.loginPopover == nil) {
NSLog(#"Login Popover is nil");
self.loginPopover = [[NSPopover alloc] init];
self.loginPopover.contentViewController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
}
if (!self.loginPopover.isShown) {
NSLog(#"Login Popover is opening");
[self.loginButton setTitle:#"Cancel"];
[self.settingsButton setEnabled:NO];
[self.send setEnabled:NO];
[self.message setEnabled:NO];
[self.loginPopover showRelativeToRect:self.loginButton.frame ofView:self.view preferredEdge:NSMinYEdge];
}
else {
NSLog(#"Login Popover is closing");
if (self.isLoggedIn) {
[self.loginButton setTitle:#"Logout"];
}
else {
[self.loginButton setTitle:#"Login"];
}
[self.settingsButton setEnabled:YES];
[self.send setEnabled:YES];
[self.message setEnabled:YES];
[self.loginPopover close];
}
}
Any help would be greatly appreciated because I have a deadline for this project.
Instead of
self.tableData = [NSMutableArray arrayWithArray:newTableData];
can you try
self.tableData = [newTableData copy];
The only thing i can think of is - is the tableData a strong property?
After this
self.tableData = [NSMutableArray arrayWithArray:newTableData];
write this snippet:
[self setTableData:tableData]
I have a Login screen which checks if the inserted Password is correct.
After that I want to switch from the Login screen to a UITabBarController.
Code from LoginViewController.m:
-(IBAction)LoginButton:(id)sender {
[PassWortEingabe resignFirstResponder];
NSString *pnssPasswortEingabe = [NSString stringWithFormat:#"%#",PassWortEingabe.text];
NSString *pnssPasswortString = [NSString stringWithFormat:#"%s","Hallo"];
if( [pnssPasswortEingabe isEqualToString: pnssPasswortString ]){
DebugTextView.text = #"Login succesfull";
//PassWortEingabe = 0;
//[PassWortEingabe resignFirstResponder];
}else{
DebugTextView.text = #"Login unsuccesfull";
//PassWortEingabe = 0;
//[PassWortEingabe resignFirstResponder];
}
}
I want jump to the UITabBarController when the Login is sucessful ...
if( [pnssPasswortEingabe isEqualToString: pnssPasswortString ]){
DebugTextView.text = #"Login succesfull";
MyTabBarClass *myTabBar = [[MyTabBarClass alloc]initWithNibName:nil bundle:nil];
myTabBar.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:myTabBar animated:YES];
//PassWortEingabe = 0;
//[PassWortEingabe resignFirstResponder];
}else{
DebugTextView.text = #"Login unsuccesfull";
//PassWortEingabe = 0;
//[PassWortEingabe resignFirstResponder];
}
It is as simple as the code below.
if( [pnssPasswortEingabe isEqualToString: pnssPasswortString ]){
// This is for iOS 5.0 and above.
UITabBarController *myTabBarController = [self.storyboard instantiateViewControllerWithIdentifier:#"myTabBarController"];
[myTabBarController setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[self presentViewController:myTabBarController animated:YES completion:^(void){
// You can set some sort of completion block here which will run when all other code finishes, this can just be nil.
}];
} else {
DebugTextView.text = #"Login unsuccesfull";
}
You can also replace this line with
[self presentViewController:myTabBarController animated:YES completion:nil];
replace with
[self presentModalViewController:myTabBarController animated:YES];
but this has been deprecated in iOS 6.0. So if you are making your app for iOS 5.0 and above you are best of using the first line so you don't have to make changes in the future.
The above code is made to use storyboards if you want to do it with nib files then change
[self.storyboard instantiateViewControllerWithIdentifier:#"myTabBarController"];
to
[[UITabBarController alloc] initWithNibName:#"myTabBarController" bundle:[NSBundle mainBundle]];
Hope this helps.
I have very weird problem
I build a simple app with UIWebView and NavigationController but the problem is when the seconds page is loading and I go back to the first page and visited a link the APP crashes and the console says nothing
Here is my code on finish loading
-(void)webViewDidFinishLoad:(UIWebView *)aWebView {
NSString *str = [aWebView stringByEvaluatingJavaScriptFromString:#"document.title"];
self.navigationItem.title = str;
[navigationActivity stopAnimating];
}
and this for the web view should start loading
if(navigationType == UIWebViewNavigationTypeOther)
{
NSURL *url2 = [request URL];
NSString *URLStr = [url2 absoluteString];
RootViewController* viewController = [[RootViewController alloc] init];
NSString *holder = [self getQueryStringInner:URLStr];
[self getQueryString:URLStr];
if([holder length] != 0 && [flag length] != 0 && !facebook )
{
appDelegate.title =#"Title";
appDelegate.query = queryString;
appDelegate.url = holder;
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
return NO;
}
}
I am really new to Objective-c and iOS development so any help will be appreciated
Any Help
Seems that the necessary step is to call [webView stopLoading] in your viewWillDisappear. Apparently the web view delegate was sending the webViewDidFinishLoading method message to a deallocated instance. Glad you got it worked out.
This is my code to present the UIImagePickerController:
// Show the media browser with our settings, then the browser will call our delegate if needed
- (BOOL) startMediaBrowserFromViewController: (UIViewController*) controller
usingDelegate: (id <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>) delegate {
if (([UIImagePickerController isSourceTypeAvailable:
UIImagePickerControllerSourceTypeSavedPhotosAlbum] == NO)
|| (delegate == nil)
|| (controller == nil))
return NO;
UIImagePickerController *mediaUI = [[[UIImagePickerController alloc] init] autorelease];
mediaUI.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
// Check for images type
NSArray * availableTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeSavedPhotosAlbum];
BOOL imgsOnlyAvailable = NO;
// Check if we have only images
for (int i = 0; i < [availableTypes count]; i++) {
// Convert the type
CFStringRef type = (CFStringRef) [availableTypes objectAtIndex:i];
if (CFStringCompare ((CFStringRef) type, kUTTypeImage, 0) == kCFCompareEqualTo) {
// We have images
imgsOnlyAvailable = YES;
break;
}
}
// Check if they are available
if (imgsOnlyAvailable == NO)
return NO;
// Displays only saved pictures from the Camera Roll album.
mediaUI.mediaTypes = [NSArray arrayWithObject:(id) kUTTypeImage];
// Hides the controls for moving & scaling pictures, or for
// trimming movies. To instead show the controls, use YES.
mediaUI.allowsEditing = NO;
mediaUI.delegate = delegate;
[controller presentModalViewController: mediaUI animated: YES];
return YES;
}
// Picker delegate
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
UIImage *originalImage;
// Handle a still image picked from a photo album
if (CFStringCompare ((CFStringRef) mediaType, kUTTypeImage, 0)
== kCFCompareEqualTo) {
originalImage = (UIImage *) [info objectForKey:
UIImagePickerControllerOriginalImage];
// Set image
self.imgPic.image = originalImage;
// Now set the button to enabled
self.btnToText.enabled = YES;
}
// Hide picker selector
[[picker parentViewController] dismissModalViewControllerAnimated: YES];
[picker release];
}
The problem is whenever I try to click an image in the UIImagePickerController nothing happens (usually it chooses the image then will dismiss the Controller)
Is there any reason why things are going wrong like this?
Thanks!
// Select the image
- (IBAction)btnSelectFileTouchUp:(id)sender {
// Start the media browser
if ([self startMediaBrowserFromViewController:self usingDelegate:self] == NO) {
// Can't open the media browser
UIAlertView * alrt = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Can't open the photo media browser in this device" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alrt show];
[alrt release];
}
}
Check out the documentation for parentViewController in the UIViewController Class Reference. Specifically this little tidbit.
Prior to iOS 5.0, if a view did not have a parent view controller and
was being presented modally, the view controller that was presenting
it would be returned. This is no longer the case. You can get the
presenting view controller using the presentingViewController
property.
In this instance, I expect that parentViewController is nil on iOS 5 and that is why the controller will not dismiss. Try replacing parentViewController with presentingViewController.
Update: You'll have to check for the existence of presentingViewController on UIViewController to provide behavior for iOS versions < 5.0.
UIViewController *dismissingController = nil;
if ([self respondsToSelector:#selector(presentingViewController)])
dismissingController = self.presentingViewController;
else
dismissingController = self.parentViewController;
[dismissingController dismissModalViewControllerAnimated:YES];