QLPreviewController - setting previewItemTitle - iphone

I can't work out how to set the previewItemTitle property for my QLPreviewController class. Its seems a bit strange as the iPhone developer document for this class says that that property is #property (readonly) which would mean that I cannot set it.
Any ideas. Thanks
My code:
QLPreviewController *preview = [[QLPreviewController alloc] init];
[preview setDataSource:self];
[self presentModalViewController:preview animated:YES];

QLPreviewController has no previewItemTitle property. You mean the QLPreviewItem protocol.
"Readonly" means that you can't set it via the property (unless it's overridden); i.e. the property does not declare a setPreviewItemTitle: method. This makes sense for the protocol: the controller does not expect to be able to set the preview item titles.
For the most basic preview item, you could use something like this:
#interface BasicPreviewItem : NSObject<QLPreviewItem>
{
}
#property (nonatomic, retain) NSURL * previewItemURL;
#property (nonatomic, copy) NSString* previewItemTitle;
#end
#implementation BasicPreviewItem
#synthesize previewItemURL, previewItemTitle;
-(void)dealloc
{
self.previewItemURL = nil;
self.previewItemTitle = nil;
[super dealloc];
}
#end
However, the point of the protocol is so that you can take any class and add -(NSURL*)previewItemURL and -(NSString*)previewItemTitle methods (e.g. if you had a music player, you could add those methods to the "Track" class and be able to preview tracks).

Related

Custom UINavigationController with button

I would like the NavigationBar to behave the same but would like to change the appearance of it. I've found so many ways of doing this online but I'm not sure which one is the best result for iOS 5.0. The navigation bar will look like this:
Since you are targeting iOS 5 i would definitely go for customizing UINavigationBar using the Appearance proxy. Then you can easily set your own images and they will apply to all navigation bars in your application without subclassing.
You can also customize the buttons in the navigation bar by customizing UIBarButtonItem. There are method like backButtonBackgroundImageForState:barMetrics: for the back button and backgroundImageForState:barMetrics: for the other buttons.
I had been looking for this thing for ages, too, without finding a straightforward solution! Thanks to an friend of mine, and sample codes, we made it with a custom navigation bar class that can be imported into any view controller class.
The .h file:
#import <UIKit/UIKit.h>
#interface NATitleBar : UIView {
NSInteger tag;
}
#property ( nonatomic) IBOutlet UIImageView *imageView;
#property ( nonatomic) IBOutlet UILabel *label;
#property ( nonatomic) IBOutlet UIButton *back;
#property ( nonatomic) IBOutlet UIButton *home;
/**
* Supports UIButton-style adding targets
*/
#end
The .m file:
#import "NATitleBar.h"
#implementation NATitleBar
#synthesize imageView;
#synthesize label;
#synthesize back;
#synthesize home;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
NSArray *views = [[NSBundle mainBundle] loadNibNamed:#"NATitleBar" owner:self options:nil];
[self addSubview:[views objectAtIndex:0]];
// customize the view a bit
//self.imageView.layer.borderWidth = 1.0;
//self.imageView.layer.borderColor = [UIColor colorWithWhite:0.4 alpha:0.4].CGColor;
//self.imageView.clipsToBounds = YES;
//self.imageView.layer.cornerRadius = 5.0;
}
return self;
}
#pragma mark - Overriden Setters / Getters
- (void)setTag:(NSInteger)aTag {
self.back.tag = aTag;
}
- (NSInteger)tag {
return self.back.tag;
}
#end
and then for the Nib file we have the following:
You can add or delete images in the Nib file to make the GUI as you wish.
Now you must import the class into any view controller you wish to have with custom navigation controller, and also define two methods (or one, if you don't want the 'home' button. in .h :
- (void) back;
in .m:
- (void)back {
[self.navigationController popViewControllerAnimated:YES];
}

NSDictionary setting to nil when passed to another class (IOS)

I am passing an NSDictionary object from one view class to another as I transition from a table view to a normal view to show details:
Passing Controller:
[tweetController setTweet:tweet];
Receiving Controller.h:
#interface TweetViewController : UIViewController {
NSDictionary *tweet;
}
#property (nonatomic, retain) NSDictionary *tweet;
Receiving Controller.m:
#implementation TweetViewController
#synthesize tweet = _tweet;
I then try to use this information to set the properties of some fields in my view:
- (void)viewDidLoad
{
[super viewDidLoad];
tweetLabel.text = [_tweet objectForKey:#"text"];
}
The result is a blank label and if I inspect the value of _tweet at this stage it is nil.
I originally had a method which set the value of tweet which I called at the same location as I am now setting the value. If I inspected the value at this stage it was fine.
I presume that the automagic setter through #synthasize is working, but somewhere else the value is being lost.
Sorry this is my first objective C anything! Thanks for any help in advance.
You are using your "tweet" instance variable, whereas the "tweet" property is synthesized to the "_tweet" variable.
You are probably calling the setTweet method after viewDidLoad executes.
I usually pass this kind of thing into a custom init method.
Alternatively, you could do the set before pushing the detail VC onto the nav stack.
Are you sure that tweetLabel isn't nil?
I've made a few corrections & optimisations to your code. You don't need to declare ivars in the header file anymore, they are generated automatically by #synthesize
- (void)dealloc; is only needed if you're not using ARC.
//.h
#interface TweetViewController : UIViewController
#property (strong, nonatomic) NSDictionary *tweet;
#property (strong, nonatomic) IBOutlet UILabel *tweetLabel
#end
//.m
#implementation TweetViewController
#synthesize tweet = _tweet;
#synthesize tweetLabel = _tweetLabel;
- (void)viewDidLoad {
[super viewDidLoad];
self.tweetLabel.text = [self.tweet objectForKey:#"text"];
}
- (void)dealloc {
[_tweet release];
[_tweetLabel release];
[super dealloc];
}
#end
Note: strong is equivalent to retain
To expand on #Rayfleck's answer, since you are new to Objective-C, your custom init method could look like this:
In TweetViewController.h:
- (id)initWithTweet:(NSDictionary*)tweet;
In TweetViewController.m:
- (id)initWithTweet:(NSDictionary*)tweet
{
self = [super init];
if (self) {
_tweet = tweet;
}
return self;
}
and then in your passing controller you'd allocate and initialize like this:
TweetViewController *tvc = [[TweetViewController alloc] initWithTweet:myTweet];

Change text in UILabel with NSMutablearray data

I'm trying to change the text of a UILabel with text from an array upon a button click, but it doesn't do anything.
#interface Test01AppDelegate : NSObject <UIApplicationDelegate> {
UILabel *helloLabel;
UIButton *hellobutton;
NSMutableArray *madWords;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UIButton *hellowButton;
#property (nonatomic, retain) IBOutlet UILabel *hellowLabel;
#property (nonatomic, retain) NSMutableArray *madWords;
- (void) madArrays;
- (IBAction)helloYall;
#end
and
#import "Test01AppDelegate.h"
#implementation Test01AppDelegate
#synthesize window = _window;
#synthesize hellowButton;
#synthesize hellowLabel;
#synthesize madWords;
- (void) madArrays {
[madWords addObject:#"Part A"];
[madWords addObject:#"Part B"];
[madWords addObject:#"Part C"];
[madWords addObject:#"Part D"];
}
- (IBAction)helloYall {
[self madArrays];
self.hellowLabel.text = [madWords objectAtIndex:0];
}
I can set the helloLabel text with
#"some text here";
and it works fine. Also, I tried copying the "madArrays" method into the "helloYall" method and it still didn't work. As I said, I can manually set the text and it works, but I'd like to pull the info from an array. Eventually, I'd like to loop through the array to grab the text on each button press, but one step at a time. Thanks.
You never create the madWords array. You need to add:
self.madWords = [NSMutableArray array];
at the top of:
- (void) madArrays {
would probably be a good place. Other possibly good places would be i the class init method or the view controller viewWillAppear method.
// Or you can try this in your init Method:
//first allocate the ivar
- (void)myInitMethod {
madArrays = [[NSMutableArray]alloc]init];
}
//then you can do anything directly to the ivar or throughout de setter
- (void)doAnythingWithiVar {
// do your stuff
}
//when you are done you can dealloc your ivar
- (void)dealloc {
[madArrays release];
[super dealloc];
}
It looks like madArrays is still nil when you come to populate it. At some point you need something like [self setMadArrays:[[NSMutableArray alloc] init]];. Also, don't forget to release madArrays in the dealloc before calling super as you'll have a memory leak.

iphone: Implement delegate in class

I am trying to call up a modal table view controller using presentModalViewController but I am not sure what to do about the delegate. The following code gives me an error:
MyRidesListView *controller = [[MyRidesListView alloc] init];
controller.delegate = self;
[self presentModalViewController:controller animated:YES];
[controller release];
Error:
Request for member 'delegate' is something not a structure or union
Now, I realized there is no delegate property in my MyRidesListView class. So, how would I add a reference to my delegate there? What am I missing here?
Generally delegates are properties defined as such:
id<NameOfDelegateProtocol> delegate;
And:
#property (nonatomic, assign) id<NameOfDelegateProtocol> delegate;
EDIT: You said your parent class is UITableViewController. You may have wanted to do this:
controller.tableView.delegate = self;
Why do you think you need a delegate? Why not just remove the "controller.delegate = self" line. Otherwise you need to implement a delegate system the way I outline below or else make MyRidesListView a subclass of a viewcontroller that implements delegates.
It looks like you cut and pasted some sample code that uses a delegate, then substituted your own viewcontroller that doesn't provide a delegate. If you don't know what the delegate is for, then just delete that line.
I'll cut and paste some actual code from one of my test programs to show you how it's done:
from the Interface file:
Add a delegate instance variable to your class and make it a property so you can use the "blah.delegate = foo" syntax to set it.
#interface BAPClient : NSObject {
CGSize imageSize;
id <BAPClientDelegate> delegate;
}
#property (nonatomic, readonly) CGSize imageSize;
#property (nonatomic, assign) id <BAPClientDelegate> delegate;
#end
// define the protocol spoken. (what the delegate must implement)
#protocol BAPClientDelegate
- (void)addTile:(BAPTile *)tile;
#end
in the implementation, you must call the delegate at the appropriate time:
- (void)deliverTile:(BAPTile *) tile {
NSLog(#"%s tile=%p",__FUNCTION__,tile);
if ([self delegate])
[[self delegate] addTile:tile];
[tile release];
}
Try to set the delegate object by the setter
[controller setDelegate:self];
This often works wonders.

How do I share an object between UIViewControllers on iPhone?

My application is a tab bar application, with a separate view controller for each tab.
I have an object in my first view controller (A) which contains all my stored application data (Please ignore NSUserDefaults for this) which needs to be accessed by the second view controller (B) when I press a button on it. How can I achieve this in the best way?
One option you have is to declare your date model as instance variables of your app delegate (as mentioned by other commenters).
Instead of referencing the app delegate as suggested by nevan an alternative is to add a property to your view controller classes (A and B) for your data model.
Say you wanted to share a data model object between your view controllers you can add a property to each:
#interface AViewController : UIViewController {
MyDataModel *model;
}
#property (nonatomic, retain) MyDataModel *model;
#end
#interface BViewController : UIViewController {
MyDataModel *model;
}
#property (nonatomic, retain) MyDataModel *model;
#end
When you initialise your view controller you can then set this property to the object context initialised previously.
You have mentioned a tab bar controller. If your view controllers are wired through IB all you have to do is to set these parameters in your application delegate applicationDidFinishLaunching: method, before the tab bar controller is displayed:
#interface MyAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate>
{
MyDataModel *model;
AViewController *aViewController;
BViewController *bViewController;
...
}
#property (retain) IBOutlet AViewController *aViewController;
#property (retain) IBOutlet BViewController *aViewController;
#end
#implementation MyAppDelegate
...
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
...
aViewController.model = model;
bViewController.model = model;
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
}
Don't forget to release the model in your view controller's dealloc method.
The alternative is to use a singleton object. An simple singleton example:
#interface MyDataModel : NSObject
{
}
+ (MyDataModel *) sharedDataModel;
#end
#implementation MyDataModel
static MyDataModel *sharedDataModel = nil;
+ (MyDataModel *) sharedDataModel
{
#synchronized(self)
{
if (sharedDataModel == nil)
{
sharedDataModel = [[MyDataModel alloc] init];
}
}
return sharedDataModel;
}
#end
You can access this data model from all your view controllers with something similar to the following:
MyDataModel *model = [MyDataModel sharedDataModel];
See also this stack overflow discussion about singletons.
The most common way I've seen this is to set up the thing you want to access in the app delegate and reference it in other places like this:
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
myStuff = appDelegate.stuff;
In the app delegate, set up a stuff variable and use #property and #synthesize as usual.
Some people say that it's not a good approach, since it's the same as using global variables, but it's very common.
I like to create a top level Model class that is a singleton and contains all the elements I might need.
It's helpful to also give it a top level load method that populates objects with just the db keys, using the hydrate/dehydrate pattern common in the Apple examples.
Typical usage in the app delegate would be simply,
[[MyModel sharedModel] load];
And then in a view controller:
NSArray *myThing1s = [[MyModel sharedModel] thing1s];
NSArray *myThing2s = [[MyModel sharedModel] thing2s];
You can then iterate over your thing1s and thing2s and when you need details, you can just call
[myThing1 hydrate];
which will populate the object.
Of course, you probably want to use CoreData to manage the persistence from 3.0 onwards.
I always create a special object called DataModel and use it's singleton sharedInstance.
And this object then holds all the app-related-data. No need for accessing the dreaded appDelegate.
DataModel.h
#import <Foundation/Foundation.h>
#class MyClass1, MyClass2;
#interface DataModel : NSObject
#property (copy, nonatomic) NSString *aString;
#property (assign) BOOL aBool;
#property (strong) MyClass1 *myObject1;
#property (strong) MyClass2 *myObject2;
+ (DataModel *)sharedModel;
#end
DataModel.m
#import "DataModel.h"
#import "Class1.h"
#import "Class2.h"
#implementation DataModel
- (id) init
{
self = [super init];
if (self)
{
_myObject1 = [[MyClass1 alloc] init];
_myObject2 = [[MyClass2 alloc] init];
aBool = NO;
aString = nil;
}
return self;
}
+ (DataModel *)sharedModel
{
static DataModel *_sharedModel = nil;
static dispatch_once_t onceSecurePredicate;
dispatch_once(&onceSecurePredicate,^
{
_sharedModel = [[self alloc] init];
});
return _sharedModel;
}
#end
And (bacause I'm lazy) i put DataModel.h in application-prefix.pch.
That way i can access my data from anywhere in the application simply by calling
[DataModel sharedModel]
Both view controllers should reference a third object (C) as their dataSource; this object (C) containing all the stored application data.
C would be, in this case, the M in the MVC.
Add to each of your ViewControllers the following declarations:
// SomeViewController.h
// Before #interface
#class MyDataSource;
// In the interface
IBOutlet MyDataSource *datasource;
#property(retain) IBOutlet MyDataSource *datasource;