I am very new to obj-c (about 1 day) and i have read the documentation on how to call methods and how to modify strings and i have used similar code in another program and it worked fine. I'm programming a simple web browser for the iphone to teach myself about WebViewController library. When i compile this it gives me the warning "'WebViewController' may not respond to '-parseURl:" at line 17 in the .m file and when i run it i throws the error "NSInvalidArgumentException" in the console.
Code for this in WebViewController.h:
#import <UIKit/UIKit.h>
#interface WebViewController : UIViewController {
IBOutlet UIWebView *webView;
IBOutlet UITextField *textField;
}
NSString *urlAddress;
NSURL *url;
NSURLRequest *requestObj;
- (IBAction)gotoAddress:(id)sender;
- (NSString*) parseURL:(NSString*)str;
#property (nonatomic, retain) UIWebView *webView;
#end
Code for this in WebViewController.m:
#import "WebViewController.h"
#implementation WebViewController
#synthesize webView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Initialization code
}
return self;
}
- (IBAction)gotoAddress:(id)sender {
urlAddress = textField.text;
urlAddress = [self parseURl:urlAddress];
url = [NSURL URLWithString:urlAddress];
requestObj = [NSURLRequest requestWithURL:url];
[webView loadRequest:requestObj];
NSLog(#"urlAddress= %s", [urlAddress cStringUsingEncoding:1]);
}
- (NSString*) parseURL:(NSString*)str {
NSLog(#"made it");
NSString *httpPart = #"http://";
if ([str rangeOfString:httpPart].location == NSNotFound) {
NSString *correctURL = [NSString stringWithFormat:#"%#%#", httpPart, str];
return correctURL;
}
else {
return str;
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[webView release];
[super dealloc];
}
#end
Thanks for the help
Objective-C (and most other languages) is case-sensitive. "URL" and "URl" are different.
urlAddress = [self parseURl:urlAddress];
should be
urlAddress = [self parseURL:urlAddress];
Related
I am trying to load files in device by using UIDocumentInteractionController in a phonegap app. I have done by following.
#import <Foundation/Foundation.h>
#import <QuickLook/QuickLook.h>
#interface FileViewer : UIViewController <UIDocumentInteractionControllerDelegate>
#end
#implementation FileViewer
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (UIViewController *) documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller {
return self;
}
- (void)viewDidLoad
{
[self viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
In Launcher.m i have done by following to show files:
CDVViewController* mainController = (CDVViewController*)[ super viewController ];
UIDocumentInteractionController *documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:fileLocation]];
FileViewer *vController = [[FileViewer alloc]init];
[mainController addChildViewController:vController];
documentInteractionController.delegate = vController;
[documentInteractionController presentPreviewAnimated:YES];
This result by giving error message:
"Presenting view controllers on detached view controllers is discouraged.
Unbalanced calls to begin/end appearance transitions for QLRemotePreviewContentController"
Thanks in advance!!
I have solved my issue by following way. It might not be the best way, so please suggest the best way also.
#interface Launcher : CDVPlugin<UIDocumentInteractionControllerDelegate>
#property (strong, nonatomic)UIViewController *navigatorController;
#property (strong, nonatomic)Launcher *launcher;
#property (strong, nonatomic)NSString *callbackId;
-(void)openFile:(CDVInvokedUrlCommand*)command;
#end
#import "Launcher.h"
#import "FileViewer.h"
#import<QuickLook/QuickLook.h>
#import <MobileCoreServices/MobileCoreServices.h>
#implementation Launcher
-(void)openFile:(CDVInvokedUrlCommand*)command{
CDVPluginResult *pluginResult = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSDictionary *params = [command.arguments objectAtIndex:0];
NSString *file = [params objectForKey:#"message"];
NSString *fileLocation = [documentsDirectory stringByAppendingFormat:#"/%#",file];
if (![fileLocation isEqual:[NSNull null]]) {
#try {
self.launcher = self;
CDVViewController *viewController = [CDVViewController new];
viewController.wwwFolderName = #"www";
viewController.startPage = #"main.html"; // page contains listview showing name of files
self.navigatorController = viewController;
UIDocumentInteractionController *documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:fileLocation]];
[[UIApplication sharedApplication].keyWindow setRootViewController:self.navigatorController];
documentInteractionController.delegate = self;
[documentInteractionController presentPreviewAnimated:YES];
}
#catch (NSException *exception) {
NSLog(#"dd : %#",[exception reason]);
}
}
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
- (UIViewController *)documentInteractionControllerViewControllerForPreview: (UIDocumentInteractionController *)controller
{
return self.navigatorController;
}
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller
{
[[UIApplication sharedApplication].keyWindow setRootViewController:self.navigatorController];
self.launcher = nil;
}
LoginViewController is my initial view controller. Email address is an input in the LoginViewController and I am trying to send it to FirstViewController. I went through a lot of solutions posted here but was unsuccessful to find a link to my answer.
Please have a look at my code and tell me where I am going wrong. I am stuck at this point from a couple of days. My main problem is that, the output of emailString shows null when I print it to see if it was carried to the FirstViewController.
FYI - I am using storyboard. I have a Tab Bar Controller which has three tabs and FirstViewController is the first tab page.
LoginViewController.h
#import <UIKit/UIKit.h>
#import "FirstViewController.h"
#interface LoginViewController : UIViewController{
NSString *email;
}
- (IBAction)LoginButton:(id)sender;
- (IBAction)CancelButton:(id)sender;
- (IBAction)dismissKeyboard:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *EmailField;
#property (weak, nonatomic) IBOutlet UITextField *PasswordField;
#end
LoginViewController.m
#import "LoginViewController.h"
#import "FirstViewController.h"
#define USERNAME #"abc#gmail.com"
#interface LoginViewController ()
#end
#implementation LoginViewController
#synthesize EmailField;
#synthesize PasswordField;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
email = [[NSString alloc] init];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)LoginButton:(id)sender {
email = EmailField.text;
if([EmailField.text isEqualToString:USERNAME])
{
FirstViewController *fvc = [[FirstViewController alloc]initWithNibName:#"FirstViewController" bundle:nil];
fvc.emailString = [[NSString alloc] initWithFormat:#"%#",EmailField.text];
// fvc.emailString = email;
[self.navigationController pushViewController:fvc animated:YES];
}
[EmailField resignFirstResponder];
}
- (IBAction)CancelButton:(id)sender {
NSLog(#"Cancel button pressed!!!");
[EmailField resignFirstResponder];
[PasswordField resignFirstResponder];
}
- (IBAction)dismissKeyboard:(id)sender {
[EmailField resignFirstResponder];
[PasswordField resignFirstResponder];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self LoginButton:nil];
[textField resignFirstResponder];
return YES;
}
#end
FirstViewController.h
#import <UIKit/UIKit.h>
#import "LoginViewController.h"
#interface FirstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *emailLabel;
#property (nonatomic, retain) NSMutableData *receivedData;
#property (copy) NSString *emailString;
FirstViewController.m
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
#synthesize emailLabel;
#synthesize receivedData;
#synthesize emailString;
- (void)viewDidLoad
{
[super viewDidLoad];
[emailLabel setText: emailString];
NSString *theURL = [NSURL URLWithString:[NSString stringWithFormat:#"http://.....email=%#",emailString]];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:theURL
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if(connection){
NSLog(#"connection successful");
NSLog(#"%#",emailString);
receivedData = [NSMutableData data];
}
else{
NSLog(#"connection failed");
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
[receivedData setLength:0];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"Success");
NSLog(#"Received %d bytes of data",[receivedData length]);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
I tried implementing prepareFOrSegue method in LoginViewController too. But it still didnot make any change. This is the code I have written in it.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([segue.identifier isEqualToString:#"showDetailSegue"])
{
NSString *email = EmailField.text;
NSLog (#"++++++++++ %#", email);
FirstViewController *fvc = [segue destinationViewController];
fvc.emailString=email;
}
}
Screenshot of Storyboard:
If you are using StoryBoards I'd strongly suggest you use segues to call the different view controllers. That way you can push vc's and pass info relatively easily.
You can override the native method prepareForSegue in your Login VC, and set the properties there. You can name your segue id as anything in the storyboard.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"firstVC"]) {
FirstViewController *firstVC = [segue destinationViewController];
firstVC.emailString = EmailField.text;
}
}
if you really want, and I'd advise against it vs. using static variables is
NSUserDefaults.
[[NSUserDefaults standardUserDefaults]
setObject:EmailField.text forKey:#"emailString"];
to get it back later
NSString *emailString = [[NSUserDefaults standardUserDefaults]
stringForKey:#"emailString"];
NSLog(#"%#",emailString);
I would save the Email and password in the IOS Keychain securely instead of passing it in between views.
https://developer.apple.com/library/ios/#documentation/security/conceptual/keychainServConcepts/iPhoneTasks/iPhoneTasks.html#//apple_ref/doc/uid/TP30000897-CH208-SW1
I got the solution.
The only three lines requires for me to add in the prepareForSegue were these three and I got my program working
FirstViewController* fvc = [[FirstViewController alloc] init];
UITabBarController *tbc = [segue destinationViewController];
fvc = (FirstViewController *) [[tbc customizableViewControllers] objectAtIndex:0];
Thanks everyone!
I try to calculate the size of a UIWebView with a given content, but without showing the view. I only need to know the size.
My Problem: When I execute the code, the delegate of the UIWebView isn't called. Why?
MessageSizeCaluclator.h
#import < Foundation/Foundation.h>
#class Message;
#interface MessageSizeCaluclator : NSObject <UIWebViewDelegate>
- (id)initWithMessage:(Message*)message;
- (void)saveSize;
#end
MessageSizeCaluclator.m
#import "Message.h"
#import "MessageSizeCaluclator.h"
#interface MessageSizeCaluclator () <UIWebViewDelegate>
#property (strong, nonatomic) Message* message;
#property (strong, nonatomic) UIWebView* webView;
#end
#implementation MessageSizeCaluclator
#synthesize message = _message;
#synthesize webView = _webView;
- (id)initWithMessage:(Message*)message
{
self = [super init];
if (self) {
_message = message;
// WebView
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
_webView.delegate = self;
}
return self;
}
- (void)saveSize
{
NSLog(#"%s message = %#", __PRETTY_FUNCTION__, _message.text);
[_webView loadHTMLString:[NSString stringWithFormat:#"<div style='font-family:Helvetica;font-size:13px;'>This is a test</div>", _message.text]
baseURL:nil];
}
#pragma mark - Web view delegate
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
- (void)webViewDidStartLoad:(UIWebView *)webView
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSLog(#"%s", __PRETTY_FUNCTION__);
}
#end
Implementation
MessageSizeCaluclator* messageSizeCalculator = [[MessageSizeCaluclator alloc] initWithMessage:message];
[messageSizeCalculator saveSize];
Add your UIWebView to some UIView, make its frame offscreen (so users can't see it). The delegate methods won't be called if UIWebView is not in the view hierarchy of the app.
My FetchVenuesView preceeds the VenuesIDController. VenuesIDController is the second tabbar item in a tabbarcontroller. FetchVenuesView is not part of the tabbar.
The first item in the tabbar is a tableview in which i can call a delegate without issue.
However when I try and call the delegate in VenuesIDController it always shows up in the log as null.
What do I do here? Do i connect the delegate in the storyboard? How?
I have a FetchVenuesViewController.h
#import "VenueTableViewController.h"
#import "VenueIDController.h"
#interface FetchVenuesViewController : UIViewController< VenueTableViewControllerDelegate, VenueIDControllerDelegate>{
NSDictionary* venueJSON;
NSDictionary* idJSON;
};
#property (strong) NSDictionary* idJSON;
- (void)VenueFetch;
- (void)IDFetch;
#end
In FetchVenuesViewController.m
#synthesize idJSON;
- (void)IDFetch {
//request some webservice
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
//save the response
if (data) {
id IDJSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
if (!IDJSON) {
//handle error
}
else {
//do something
}
} else {
// fetch failed
}
activityIndicator.hidden = NO;
}
-(NSDictionary *)getID{
[self IDfetch];
NSLog(#"json%#",idJSON);
return idJSON;
}
In VenueIDController.h
#protocol VenueIDControllerDelegate;
#interface VenueIDController : UIViewController{
}
#property (assign) id <VenueIDControllerDelegate> delegate;
-(IBAction)getIDData:(id)sender;
#end
#protocol VenueIDControllerDelegate <NSObject>
-(NSDictionary *)getID;
#end
and in VenueIDController.m
#interface VenueIDController (){
NSMutableArray* IDData;
UIImage* IDBarcode;
}
-(void) displayIDData:(NSDictionary*)data;
#end
#implementation VenueIDController
#synthesize delegate;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
VenueIDController *vid = [[VenueIDController alloc] init];
vid.delegate = self;
NSLog(#"%#",vid);
}
return self;
}
-(void) displayIDData:(NSDictionary*)data{
[delegate getID];
NSDictionary* idJSON = data;
}
Your init on VenueIDController appears wrong. you're already in an init, so you don't need to create another one. instead you should have self.delegate = self. The vid object you are creating there isn't going to be retained.
I have created a singleton for my MusicBackground. And I receive a line code of imcomplete implementation of this line #implementation MyBgMusic. Can anyone tell me why ? Below is the code:
#import "MyBgMusic.h"
static MyBgMusic *sharedMyManager = nil;
#implementation MyBgMusic
#synthesize player,playBgMusic;
#pragma mark -
#pragma mark Singleton Methods
+ (MyBgMusic*)sharedInstance {
static MyBgMusic *_sharedInstance;
if(!_sharedInstance) {
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[super allocWithZone:nil] init];
});
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#if (!__has_feature(objc_arc))
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (id)autorelease {
return self;
}
- (void)dealloc
{
[MyBgMusic release];
[playBgMusic release];
[player release];
[super dealloc];
}
#endif
#pragma mark -
#pragma mark Custom Methods
- (void)viewDidLoad
{
NSString *path = [[NSBundle mainBundle] pathForResource:#"music" ofType:#"mp3"];
self.player=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
player.delegate = self;
[player play];
player.numberOfLoops = -1;
[super viewDidLoad];
}
#end
For the M file, below is the code:
#import <Foundation/Foundation.h>
#import <AVFoundation/AVAudioPlayer.h>
#interface MyBgMusic : UIViewController <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
UIButton *playBgMusic;
}
#property (nonatomic, retain) IBOutlet AVAudioPlayer *player;
#property (nonatomic, retain) IBOutlet UIButton *playBgMusic;
+ (id)sharedManager;
-(IBAction) toggleMusic;
#end
And how do I reference to my toggle button: Below is the code :
- (IBAction)toggleMusic {
if ([self.player isPlaying] == YES) {
[self.player stop];
} else {
[self.player play];
}
self.playBgMusic.enabled = YES;
}
It means that your MyBgMusic class isn't doing everything it promised to do in its header file, which includes being a UIViewController and implementing the AVAudioPlayerDelegate protocol. I'm not familiar with exactly what the AVAudioPlayerDelegate is, but it's quite possible that your class doesn't implement all of the required methods.
Also, you're declaring methods +(id)sharedManager and -(IBAction)toggleMusic, but I don't see them anywhere in the implementation file. That would be a case of promising something in the header and not implementing it in the class.
It would help if you posted the actual error message.
That error means your #implementation section does not contain everything described in the #interface section.
I can see two problems.
First you need to place this code:
- (IBAction)toggleMusic {
...
}
Somewhere in between #implementation and #end.
And you also need to rename the line + (MyBgMusic*)sharedInstance to + (id)sharedManager.
EDIT:
To access the toggle music method elsewhere in your code, you would do:
[[MyBgMusic sharedManager] toggleMusic];
Your +(id)sharedManagerimplementation is called +(id)sharedInstance. Just guessing, but it seems they are supposed to do the same.