UIWebView Delegate : webViewDidFinishLoad not being called - objective-c

I try to load an array of UIWebView with delegate associated.
for (GDataXMLElement *post in array) {
NSString *msg = [[[post elementsForName:#"message"] objectAtIndex:0] stringValue];
UIWebView *web_view = [[UIWebView alloc] initWithFrame:CGRectZero];
web_view.delegate = self;
[web_view loadHTMLString:msg baseURL:nil];
NSLog(#"Msg: %#", msg);
}
where msg is some HTML codes reading from XML. XML is loaded properly (verified by the NSLog line). Then in my webViewDidFinishLoad::
- (void)webViewDidFinishLoad:(UIWebView *)webView {
CGRect frame = webView.frame;
frame.size.height = 1;
webView.frame = frame;
CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
frame.size = fittingSize;
webView.frame = frame;
NSLog(#"WebView Height: %.1f", webView.frame.size.height);
[webviews addObject:webView];
}
I auto resize the web views and add them to a NSMutableArray called webviews. However, webViewDidFinishLoad is not called.
In the header .h file, the interface is defined as:
#interface ViewController : UIViewController<UIWebViewDelegate>
What did I miss? Is the web_view in the loop get disposed ?
p.s. It looks like a duplicate of this question, but it isn't.
Alternate Approach 1
Declared at .h:
#property (nonatomic, weak) NSMutableArray *webviews;
Then for implementation:
for (GDataXMLElement *post in array) {
NSString *msg = [[[post elementsForName:#"message"] objectAtIndex:0] stringValue];
UIWebView *web_view = [[UIWebView alloc] initWithFrame:CGRectZero];
web_view.delegate = self;
[web_view loadHTMLString:msg baseURL:nil];
NSLog(#"Msg: %#", msg);
[self.webviews addObject:web_view];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    CGRect frame = webView.frame;
    frame.size.height = 1;
    webView.frame = frame;
    CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
    frame.size = fittingSize;
    webView.frame = frame;
    NSLog(#"WebView Height: %.1f", webView.frame.size.height);
}
Alternate Approach 2
Instead of instantiating UIWebView in for-loop, I put it in header file.
#interface ViewController : UIViewController<UIWebViewDelegate> {
UIWebView *web_view;
}
Then change the for-loop:
for (GDataXMLElement *post in array) {
NSString *msg = [[[post elementsForName:#"message"] objectAtIndex:0] stringValue];
web_view = [[UIWebView alloc] initWithFrame:CGRectZero];
web_view.delegate = self;
[web_view loadHTMLString:msg baseURL:nil];
NSLog(#"Msg: %#", msg);
[self.webviews addObject:web_view];
}
In this approach, only the delegate of last message gets called.
Summary & Highlights:
My objectives:
Load all UIWebView with variable-size contents
The web views should auto fit the size of contents ( without scrolling ); that's why webViewDidFinishLoad is required.
Arrange the web views properly on current view ( or probably a UIScrollView ) in order to make it not overlapped.

You should do like this,
#interface UIViewController <UIWebViewDelegate>
{
}
#property(nonatomic, strong)NSMutableArray *webViews;
#end
////////////////
#implementation UIViewController
-(void)viewDidLoad
{
[super viewDidLoad];
webViews = [[NSMutableArray alloc] init];
for (GDataXMLElement *post in array)
{
NSString *msg = [[[post elementsForName:#"message"] objectAtIndex:0] stringValue];
UIWebView *web_view = [[UIWebView alloc] initWithFrame:CGRectZero];
web_view.delegate = self;
[web_view loadHTMLString:msg baseURL:nil];
NSLog(#"Msg: %#", msg);
[self.webViews addObject:web_view];
//i don't know why would you not add these web-views on the view controller,
// but still, here is the addition of these.
[self.view addSubView:web_view];
}
}
#end
This should make the web-views call the delegate properly on load.

If you're using ARC, the web_view is deallocated at the end of the for loop.

Here is my final solution ( hope it is useful for others ):
In Storyboard, I added a UIScrollView in the view controller, and link it with the IBOutlet.
Header file:
#import <UIKit/UIKit.h>
#import "GDataXMLNode.h"
#interface ViewController : UIViewController<UIWebViewDelegate> {
IBOutlet UIScrollView *scroll_view;
}
#property (nonatomic, strong) UIWebView *web_view;
#end
Implementation file:
float currentY;
NSArray *array;
int count;
GDataXMLDocument *doc;
- (void)viewDidLoad
{
[super viewDidLoad];
currentY = 0;
count = 0;
[self loadXML];
}
- (void)loadXML {
// Some codes to load the XML contents into array variable
[self loadWebView];
}
- (void)loadWebView {
if(count < array.count) {
GDataXMLElement *post = [array objectAtIndex:count];
NSString *msg = [[[post elementsForName:#"message"] objectAtIndex:0] stringValue];
count++;
self.web_view = [[UIWebView alloc] initWithFrame:CGRectMake(10, currentY, 300, 1.0f)];
self.web_view.delegate = self;
[self.web_view setHidden:YES];
[self.web_view loadHTMLString:msg baseURL:nil];
[scroll_view addSubview:self.web_view];
} else {
// end the process
[scroll_view setContentSize:CGSizeMake(320, currentY + 30)];
return;
}
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
CGRect frame = webView.frame;
frame.size.height = 1;
webView.frame = frame;
CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
frame.size = fittingSize;
webView.frame = frame;
[webView setHidden:NO];
currentY += webView.frame.size.height + 20.0f; // 20.0f is spaces between posts
NSLog(#"WebView Height: %.1f", webView.frame.size.height);
[self loadWebView];
}

Related

Which third party Imageview class should i used?

My requirement is :
Need to show image in imageview from server URL & save it for offline use also.
But There may be chances that same URL image can be updated.
I tried EGOImageview,AsyncImageview,FXImageview,Haneke thsese all classes i tried.
my first part of requirement is achieved. but not second..i.e if "xxxxx" link image is shown for first time....if on that same link image is upadated ,app shows old image only...
You can use the below class that will full fill your requirement
DImageView.h
#import <UIKit/UIKit.h>
#interface DImageView : UIImageView
#property (nonatomic, strong) UIActivityIndicatorView *activityView;
- (void)processImageDataWithURLString:(NSString *)urlString;
+ (UIImage *)getSavedImage :(NSString *)fileName;
+ (void)saveImageWithFolderName:(NSString *)folderName AndFileName:(NSString *)fileName AndImage:(NSData *) imageData;
DImageView.m
#import "DImageView.h"
#define IMAGES_FOLDER_NAME #"DImages"
#implementation DImageView
#pragma mark - App Life Cycle
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
}
return self;
}
- (void)dealloc
{
self.activityView = nil;
[super dealloc];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self initWithFrame:[self frame]];
}
return self;
}
#pragma mark - Download images
- (void)processImageDataWithURLString:(NSString *)urlString //andBlock:(void (^)(UIImage * img))processImage
{
#autoreleasepool
{
UIImage * saveImg = [DImageView getSavedImage:urlString];
if (saveImg)
{
dispatch_queue_t callerQueue = dispatch_get_main_queue();
dispatch_async(callerQueue, ^{
#autoreleasepool
{
[self setImage:saveImg];
}
});
}
else
{
[self showActivityIndicator];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
dispatch_queue_t callerQueue = dispatch_get_main_queue();
dispatch_queue_t downloadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
__block NSError* error = nil;
dispatch_async(downloadQueue, ^{
NSData * imageData = [[[NSData dataWithContentsOfURL:url options:NSDataReadingUncached error:&error] retain] autorelease];
if (error)
{
NSLog(#"DImg Error %#", [error debugDescription]);
}
else
{
dispatch_async(callerQueue, ^{
#autoreleasepool
{
UIImage *image = [UIImage imageWithData:imageData];
[self setImage:image];
[self hideActivityIndicator];
/* Below code is to save image*/
[DImageView saveImageWithFolderName:IMAGES_FOLDER_NAME AndFileName:urlString AndImage:imageData];
}
});
}
});
dispatch_release(downloadQueue);
}
}
}
#pragma mark - File Save methods
+ (void)saveImageWithFolderName:(NSString *)folderName AndFileName:(NSString *)fileName AndImage:(NSData *) imageData
{
#autoreleasepool
{
NSFileManager *fileManger = [NSFileManager defaultManager] ;
NSString *directoryPath = [NSString stringWithFormat:#"%#/%#",[DImageView applicationDocumentsDirectory],folderName] ;
if (![fileManger fileExistsAtPath:directoryPath])
{
NSError *error = nil;
[fileManger createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error];
}
fileName = [DImageView fileNameValidate:fileName];
NSString *filePath = [NSString stringWithFormat:#"%#/%#",directoryPath,fileName] ;
BOOL isSaved = [imageData writeToFile:filePath atomically:YES];
if (!isSaved)
{
NSLog(#" ** Img Not Saved");
}
}
}
+ (NSString *)applicationDocumentsDirectory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}
+ (UIImage *)getSavedImage :(NSString *)fileName
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
fileName = [DImageView fileNameValidate:fileName];
NSFileManager * fileManger = [NSFileManager defaultManager] ;
NSString * directoryPath = [NSString stringWithFormat:#"%#/%#",[DImageView applicationDocumentsDirectory],IMAGES_FOLDER_NAME] ;
NSString * filePath = [NSString stringWithFormat:#"%#/%#",directoryPath,fileName] ;
if ([fileManger fileExistsAtPath:directoryPath])
{
UIImage *image = [UIImage imageWithContentsOfFile:filePath] ;
if (image)
{
return image;
}
else
{
NSLog(#"** Img Not Found **");
return nil;
}
}
[pool release];
return nil;
}
+ (NSString*) fileNameValidate : (NSString*) name
{
name = [name stringByReplacingOccurrencesOfString:#"://" withString:#"##"];
name = [name stringByReplacingOccurrencesOfString:#"/" withString:#"#"];
name = [name stringByReplacingOccurrencesOfString:#"%20" withString:#""];
return name;
}
#pragma mark - Activity Methods
- (void) showActivityIndicator
{
self.activityView = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
self.activityView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
self.activityView.hidesWhenStopped = TRUE;
self.activityView.backgroundColor = [UIColor clearColor];
self.activityView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
[self addSubview:self.activityView];
[self.activityView startAnimating];
}
- (void) hideActivityIndicator
{
CAAnimation *animation = [NSClassFromString(#"CATransition") animation];
[animation setValue:#"kCATransitionFade" forKey:#"type"];
animation.duration = 0.4;;
[self.layer addAnimation:animation forKey:nil];
[self.activityView stopAnimating];
[self.activityView removeFromSuperview];
for (UIView * view in self.subviews)
{
if([view isKindOfClass:[UIActivityIndicatorView class]])
[view removeFromSuperview];
}
}
What will this class do ?
It will download images from server and save it to application document directory And get it from local if its available.
How to use that ?
Set DImageView class in your nib file for UIImageView.
Then you can simply use it as below in your .m file.
[imgViewName processImageDataWithURLString:imageURl];
You should take a look at SDWebImage. It's one of the most used UIImageView category right now and offers a lot of features, including caching.
Have a look at this part of the documentation to learn how to refresh your cache with it: Handle image refresh

transitionWithView gets called repeatedly after ViewController is dismissed

This is in a ModalViewController using StoryBoard and ARC
When I dismiss the view I see this line...
NSLog(#"%d %#",[imgArray count],fileName); ... being printed over and over again.
How do I kill the functions transitionWithView/animateWithDuration when the view is dismissed?
Missing something quite crucial!
.h
#import <UIKit/UIKit.h>
#interface InfoVC : UIViewController
#property (weak, nonatomic) IBOutlet UIImageView *imageview;
#property (weak, nonatomic) IBOutlet UIScrollView *scrollview;
#end
.m
#import "InfoVC.h"
#import <QuartzCore/QuartzCore.h>
#interface InfoVC ()
#end
#implementation InfoVC {
int randomInt;
NSArray *imgs;
NSMutableArray *imgArray;
NSTimer *myTimer;
NSTimer *myTimer2;
NSString *currentImg;
}
- (void)viewDidLoad
{
[super viewDidLoad];
imgs = [NSArray arrayWithObjects:
#"01.jpg",
#"02.jpg",
#"03.jpg",
nil];
imgArray = [imgs mutableCopy];
[self initialImage];
}
- (void)initialImage
{
_imageview.contentMode = UIViewContentModeLeft;
int rnd = [imgArray count];
randomInt = (arc4random()%rnd);
currentImg = [imgArray objectAtIndex:randomInt];
UIImage *image = [UIImage imageNamed:currentImg];
[_imageview setImage:image];
_imageview.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
_scrollview.contentSize = image.size;
_scrollview.contentOffset = CGPointMake(-150.0, 0.0);
[imgArray removeObjectAtIndex: randomInt];
[self animate];
}
- (void)randomImage
{
if ([imgArray count]==0) {
imgArray = [imgs mutableCopy];
}
int rnd = [imgArray count];
randomInt = (arc4random()%rnd);
NSString *fileName = [imgArray objectAtIndex:randomInt];
NSLog(#"%d %#",[imgArray count],fileName);
[imgArray removeObjectAtIndex: randomInt];
UIImage * toImage = [UIImage imageNamed:fileName];
void (^completion)(void) = ^{
[self animate];
};
[UIView transitionWithView:self.view
duration:1.75f
options:UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowUserInteraction
animations:^
{
_imageview.image = toImage;
}
completion:^(BOOL finished)
{
completion();
}
];
}
- (void)animate{
CGPoint offset = _scrollview.contentOffset;
float flt = 150.0;
if (_scrollview.contentOffset.x == flt)
{
offset.x = 0.0 ;
}
else
{
offset.x = flt ;
}
void (^completion2)(void) = ^{
[self randomImage];
};
[UIView animateWithDuration:5.0 delay:0 options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseIn
animations:^{
_scrollview.contentOffset = offset;
}completion:^(BOOL completed){
completion2();
}
];
}
- (void)viewDidUnload
{
[super viewDidUnload];
[_scrollview.layer removeAllAnimations];
[_imageview.layer removeAllAnimations];
}
- (IBAction)dismissInfo:(id)sender
{
[_scrollview.layer removeAllAnimations];
[_imageview.layer removeAllAnimations];
[self dismissModalViewControllerAnimated:YES];
}
I tried using a gazillion things retro fitting transitionWithView with CABasicAnimation, using NSTimer etc.
In the end I just did:
[_imageview removeFromSuperview];
when dismissing the view and all was great.
But from other posts on here it appears there is a bug hen when applying an alpha transition to a UIScrollview - the reference to the view is lost when it's transparent.

No known class method for selector 'sharedStore'

Have a singleton class for BNRItemStore, but when I tried to call it, I get the above error which causes an ARC issue. Have commented out the error.
DetailViewController.m
#import "DetailViewController.h"
#import "BNRItem.h"
#import "BNRImageStore.h"
#import "BNRItemStore.h"
#implementation DetailViewController
#synthesize item;
-(id)initForNewItem:(BOOL)isNew
{
self = [super initWithNibName:#"DetailViewController" bundle:nil];
if(self){
if (isNew) {
UIBarButtonItem *doneItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self
action:#selector(save:)];
[[self navigationItem] setRightBarButtonItem:doneItem];
UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:#selector(cancel:)];
[[self navigationItem] setLeftBarButtonItem:cancelItem];
}
}
return self;
}
-(id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle
{
#throw [NSException exceptionWithName:#"Wrong initializer"
reason:#"Use initForNewItem:"
userInfo:nil];
return nil;
}
-(void)viewDidLoad
{
[super viewDidLoad];
UIColor *clr = nil;
if ([[UIDevice currentDevice]userInterfaceIdiom]== UIUserInterfaceIdiomPad) {
clr = [UIColor colorWithRed:0.875 green:0.88 blue:0.91 alpha:1];
} else {
clr = [UIColor groupTableViewBackgroundColor];
}
[[self view]setBackgroundColor:clr];
}
- (void)viewDidUnload {
nameField = nil;
serialNumberField = nil;
valueField = nil;
dateLabel = nil;
imageView = nil;
[super viewDidUnload];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[nameField setText:[item itemName]];
[serialNumberField setText:[item serialNumber]];
[valueField setText:[NSString stringWithFormat:#"%d", [item valueInDollars]]];
// Create a NSDateFormatter that will turn a date into a simple date string
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
// Use filtered NSDate object to set dateLabel contents
[dateLabel setText:[dateFormatter stringFromDate:[item dateCreated]]];
NSString *imageKey = [item imageKey];
if (imageKey) {
// Get image for image key from image store
UIImage *imageToDisplay = [[BNRImageStore sharedStore]imageForKey:imageKey];
// Use that image to put on the screen in imageview
[imageView setImage:imageToDisplay];
} else {
// Clear the imageview
[imageView setImage:nil];
}
}
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Clear first responder
[[self view]endEditing:YES];
// "Save" changes to item
[item setItemName:[nameField text]];
[item setSerialNumber:[serialNumberField text]];
[item setValueInDollars:[[valueField text] intValue]];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)io
{
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
return YES;
} else {
return (io==UIInterfaceOrientationPortrait);
}
}
-(void)setItem:(BNRItem *)i
{
item = i;
[[self navigationItem] setTitle:[item itemName]];
}
- (IBAction)takePicture:(id)sender {
if ([imagePickerPopover isPopoverVisible]) {
// If the popover is already up, get rid of it
[imagePickerPopover dismissPopoverAnimated:YES];
imagePickerPopover = nil;
return;
}
UIImagePickerController *imagePicker =
[[UIImagePickerController alloc]init];
// If our device has a camera, we want to take a picture, otherwise, we
// just pick from the photo library
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
} else {
[imagePicker setSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
// This line of code will generate a warning right now, ignore it
[imagePicker setDelegate:self];
//Place image picker on the screen
// Check for iPad device before instantiating the popover controller
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
// Create a new popover controller that will display the imagepicker
imagePickerPopover = [[UIPopoverController alloc]initWithContentViewController:imagePicker];
[imagePickerPopover setDelegate:self];
// Display the popover controller; sender
// is the camera bar button item
[imagePickerPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
} else {
[self presentViewController:imagePicker animated:YES completion:nil];
}
}
}
-(void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
NSLog(#"User dismissed popover");
imagePickerPopover = nil;
}
- (IBAction)backgroundTapped:(id)sender {
[[self view]endEditing:YES];
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
NSString *oldKey = [item imageKey];
// Did the item already have an image?
if (oldKey) {
// Delete the old image
[[BNRImageStore sharedStore]deleteImageForKey:oldKey];
}
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Create a CFUUID object - it knows how to create unique identifier strings
CFUUIDRef newUniqueID = CFUUIDCreate(kCFAllocatorDefault);
// Create a string from unique identifier
CFStringRef newUniqueIDString = CFUUIDCreateString(kCFAllocatorDefault, newUniqueID); // Incompatible integer to pointer conversion initializing
// Use that unique ID to set our item's imageKey
NSString *key = (__bridge NSString *)newUniqueIDString;
[item setImageKey:key];
// Store image in the BNRImageStore with this key
[[BNRImageStore sharedStore] setImage:image forKey:[item imageKey]];
CFRelease(newUniqueIDString);
CFRelease(newUniqueID);
[imageView setImage:image];
if ([[UIDevice currentDevice]userInterfaceIdiom]==UIUserInterfaceIdiomPad) {
// If on the phone, the image picker is presented modally. Dismiss it.
[self dismissViewControllerAnimated:YES completion:nil];
} else {
// If on the pad, the image picker is in the popover. Dismiss the popover.
[imagePickerPopover dismissPopoverAnimated:YES];
imagePickerPopover = nil;
}
}
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
-(void)save:(id)sender
{
[[self presentingViewController]dismissViewControllerAnimated:YES
completion:nil];
}
-(void)cancel:(id)sender
{
// If the user cancelled, then remove the BNRItem from the store
[[BNRItemStore sharedStore]removeItem:item]; // No known class method for selector 'sharedStore'
[[self presentingViewController]dismissViewControllerAnimated:YES completion:nil];
}
DetailViewController.h
#import <UIKit/UIKit.h>
#class BNRItem;
#interface DetailViewController : UIViewController <UINavigationControllerDelegate, UIImagePickerControllerDelegate,UITextFieldDelegate, UIPopoverControllerDelegate>
{
__weak IBOutlet UITextField *nameField;
__weak IBOutlet UITextField *serialNumberField;
__weak IBOutlet UITextField *valueField;
__weak IBOutlet UILabel *dateLabel;
__weak IBOutlet UIImageView *imageView;
UIPopoverController *imagePickerPopover;
}
#property(nonatomic,strong)BNRItem *item;
-(id)initForNewItem:(BOOL)isNew;
- (IBAction)takePicture:(id)sender;
- (IBAction)backgroundTapped:(id)sender;
#end
BNRItemStore.m
#import "BNRItemStore.h"
#import "BNRItem.h"
#implementation BNRItemStore
+ (BNRItemStore *)defaultStore
{
static BNRItemStore *defaultStore = nil;
if(!defaultStore)
defaultStore = [[super allocWithZone:nil] init];
return defaultStore;
}
+ (id)allocWithZone:(NSZone *)zone
{
return [self defaultStore];
}
- (id)init
{
self = [super init];
if(self) {
allItems = [[NSMutableArray alloc] init];
}
return self;
}
- (void)removeItem:(BNRItem *)p
{
[allItems removeObjectIdenticalTo:p];
}
- (NSArray *)allItems
{
return allItems;
}
- (void)moveItemAtIndex:(int)from
toIndex:(int)to
{
if (from == to) {
return;
}
// Get pointer to object being moved so we can re-insert it
BNRItem *p = [allItems objectAtIndex:from];
// Remove p from array
[allItems removeObjectAtIndex:from];
// Insert p in array at new location
[allItems insertObject:p atIndex:to];
}
- (BNRItem *)createItem
{
BNRItem *p = [BNRItem randomItem];
[allItems addObject:p];
return p;
}
#end
BNRItemStore.h
#import <Foundation/Foundation.h>
#class BNRItem;
#interface BNRItemStore : NSObject
{
NSMutableArray *allItems;
}
+ (BNRItemStore *)defaultStore;
- (void)removeItem:(BNRItem *)p;
- (NSArray *)allItems;
- (BNRItem *)createItem;
- (void)moveItemAtIndex:(int)from
toIndex:(int)to;
#end
You are calling +sharedStore on BNRItemStore where your error occurs. This is because it really does not exist according to the code you posted.
All of the others calling +sharedStore are using the one presumably made available by BNRImageStore which you didn't provide. I assume it exists in that class? :)
In short, change:
[[BNRItemStore sharedStore]removeItem:item];
to
[[BNRImageStore sharedStore]removeItem:item];

Object is deallocated don't know why?

Please help me I am not able to understand why this is happening there a object _getProductType is deallocate without any reason. please take a look, I am not able to figure out what is happening , if you can help me I will be very thank full to you, Thanks in advance
//
// ProductComponentViewController.m
// TurfNutritionTool
//
// Created by Aashish Joshi on 10/14/11.
// Copyright 2011 Abacus Consultancy Services. All rights reserved.
//
#import "ProductComponentViewController.h"
#import <QuartzCore/QuartzCore.h>
#implementation ProductComponentViewController
#synthesize productTableView = _productTableView;
#synthesize productTypeSelector = _productTypeSelector;
#synthesize turftypePopover = _turftypePopover;
#synthesize gotTurftype = _gotTurftype;
#synthesize resultProduct = _resultProduct;
#synthesize productTableCellStyle = _productTableCellStyle;
#synthesize dbObject = _dbObject;
#synthesize getProductType = _getProductType;
#define Granular #"G"
#define Liquid #"L"
#define Tankmix #"T"
#define AllProduct #"A"
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// D o any additional setup after loading the view from its nib.
UIColor *_background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"main_bg.png"]];
self.view.backgroundColor = _background;
[_background release];
// init the segment button value
[productTypeSelector setSelectedSegmentIndex:0];
_getProductType = [[NSString alloc] initWithString:AllProduct];
// set table delegate
_productTableView.delegate = self;
// load the product
[self loadProductComponentValues];
// Set the table view to be rounded
[[_productTableView layer] setCornerRadius:5.0];
}
- (void)viewDidUnload
{
[self setProductTableView:nil];
[self setProductTypeSelector:nil];
_productTableView = nil;
_productTypeSelector = nil;
_turftypePopover = nil;
_gotTurftype = nil;
_resultProduct = nil;
_productTableCellStyle = nil;
_getProductType = nil;
[_getProductType release];
[_productTableView release];
[_productTypeSelector release];
[_turftypePopover release];
[_gotTurftype release];
[_resultProduct release];
[_productTableCellStyle release];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
- (void)dealloc {
[_getProductType release];
[_productTableView release];
[_productTypeSelector release];
[_turftypePopover release];
[_gotTurftype release];
[_resultProduct release];
[_productTableCellStyle release];
[super dealloc];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// #warning Incomplete method implementation.
// Return the number of rows in the section.
// NSLog(#"%s", __FUNCTION__);
return [self.resultProduct count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
[[NSBundle mainBundle] loadNibNamed:#"productContentTableCellStyle" owner:self options:nil];
cell = _productTableCellStyle;
self.productTableCellStyle = nil;
}
NSDictionary * _productRow = [_dbObject getProductdetail:[self.resultProduct objectAtIndex:indexPath.row]];
// Configure the cell...
UILabel* _label = (UILabel *)[cell viewWithTag:1];
NSString* _linkcode = [_productRow objectForKey:#"linkcode"];
_label.text = _linkcode;
_label = (UILabel *)[cell viewWithTag:2];
NSString* _description = [_productRow objectForKey:#"description"];
_label.text = _description;
_label = (UILabel *)[cell viewWithTag:3];
NSString* _productcode = [_productRow objectForKey:#"productcode"];
_label.text = _productcode;
_label = (UILabel *)[cell viewWithTag:4];
NSString* _weight = [_productRow objectForKey:#"weight"];
_label.text = _weight;
_label = (UILabel *)[cell viewWithTag:6];
NSNumber* _costperBag = [[NSNumber alloc] initWithFloat:[[_dbObject getUserProductCost:[self.resultProduct objectAtIndex:indexPath.row]] floatValue]];
_label.text = [#"$ " stringByAppendingString:[_costperBag stringValue]];
[_costperBag autorelease];
_getProductType = [_productRow objectForKey:#"producttype"];
if ([_getProductType isEqualToString:#"G"]) {
_label = (UILabel *)[cell viewWithTag:10];
NSString* _weightTag = [[NSString alloc] initWithString:#"Weight in Lbs"];
_label.text = _weightTag;
[_weightTag autorelease];
_label = (UILabel *)[cell viewWithTag:11];
NSString* _SGNTag = [[NSString alloc] initWithString:#"SGN"];
_label.text = _SGNTag;
[_SGNTag autorelease];
_label = (UILabel *)[cell viewWithTag:5];
NSString* _sgn = [_productRow objectForKey:#"sgn"];
_label.text = _sgn;
} else if([_getProductType isEqualToString:#"L"]) {
_label = (UILabel *)[cell viewWithTag:10];
NSString* _weightTag = [[NSString alloc] initWithString:#"Weight in Ozs"];
_label.text = _weightTag;
[_weightTag autorelease];
_label = (UILabel *)[cell viewWithTag:11];
NSString* _SGTag = [[NSString alloc] initWithString:#"SG"];
_label.text = _SGTag;
[_SGTag autorelease];
_label = (UILabel *)[cell viewWithTag:5];
NSString* _sgn = [_productRow objectForKey:#"sg"];
_label.text = _sgn;
} else if([_getProductType isEqualToString:#"T"]) {
_label = (UILabel *)[cell viewWithTag:10];
NSString* _weightTag = [[NSString alloc] initWithString:#"Weight in Ozs"];
_label.text = _weightTag;
[_weightTag autorelease];
_label = (UILabel *)[cell viewWithTag:11];
NSString* _SGTag = [[NSString alloc] initWithString:#"SG"];
_label.text = _SGTag;
[_SGTag autorelease];
_label = (UILabel *)[cell viewWithTag:5];
NSString* _sgn = [_productRow objectForKey:#"sg "];
_label.text = _sgn;
}
return cell;
}
- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIColor *_background = [[[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"toolbar_bkg.png"]] autorelease];
UIView* _customView = [[[UIView alloc]initWithFrame:CGRectMake(10.0, 0.0, 300.0, 44.0)]autorelease];
_customView.backgroundColor = _background;
return _customView;
}
- (UIView *) tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
UIColor *_background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"toolbar_bkg.png"]];
UIView* _customView = [[[UIView alloc]initWithFrame:CGRectMake(10.0, 0.0, 300.0, 44.0)]autorelease];
_customView.backgroundColor = _background;
[_background release];
return _customView ;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
if (_delegate != nil) {
NSString *_selectedTurftype = [_getTurftype objectAtIndex:indexPath.row];
[_delegate getSelectedTurftype:_selectedTurftype];
}
*/
// NSDictionary * _productRow = [_dbObject getProductdetail:[self.resultProduct objectAtIndex:indexPath.row]];
// Animate the deselection
[self.productTableView deselectRowAtIndexPath:[self.productTableView indexPathForSelectedRow] animated:YES];
CGRect _popoverRect = CGRectMake(800.0f, 380.0f, 10.0f, 10.0f);
if ([_turftypePopover isPopoverVisible]) {
[_turftypePopover dismissPopoverAnimated:YES];
}
else
{
ProductDetailViewController* _productDetailViewControllerObj = [[ProductDetailViewController alloc] init];
_turftypePopover = [[UIPopoverController alloc]
initWithContentViewController:_productDetailViewControllerObj];
_productDetailViewControllerObj.dbObject = _dbObject;
[_productDetailViewControllerObj getSelectedProductId:[self.resultProduct objectAtIndex:indexPath.row] ];
[_productDetailViewControllerObj release];
_turftypePopover.popoverContentSize = CGSizeMake(360, 500);
[_turftypePopover presentPopoverFromRect:_popoverRect inView:self.view
permittedArrowDirections:0 animated:YES];
}
[self.productTableView deselectRowAtIndexPath:[self.productTableView indexPathForSelectedRow] animated:YES];
}
#pragma mark - ProductComponentViewController lifecycle methods
- (IBAction)laodTurftype:(id)sender {
[self initAllTheProduct];
if (_getProductType == (id)[NSNull null] && _getProductType == nil) {
_getProductType = [NSString stringWithString:AllProduct];
}
if ([_turftypePopover isPopoverVisible]) {
[_turftypePopover dismissPopoverAnimated:YES];
}
else
{
TurftypePopoverViewController* _turftypeControllerObj = [[TurftypePopoverViewController alloc] init];
_turftypeControllerObj.dbObject = _dbObject;
_turftypeControllerObj.delegate = self;
_turftypePopover = [[UIPopoverController alloc]
initWithContentViewController:_turftypeControllerObj];
[_turftypeControllerObj release];
_turftypePopover.popoverContentSize = CGSizeMake(150, 225);
[_turftypePopover presentPopoverFromBarButtonItem:sender
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
}
- (IBAction)setProductType:(id)sender {
switch (_productTypeSelector.selectedSegmentIndex) {
case 0:
_getProductType = [NSString stringWithString:AllProduct];
break;
case 1:
_getProductType = [NSString stringWithString:Granular];
break;
case 2:
_getProductType = [NSString stringWithString:Liquid];
break;
case 3:
_getProductType = [NSString stringWithString:Tankmix];
break;
}
[self loadProductComponentValues];
// Check Point
[TestFlight passCheckpoint:#"SET_PRODUCT_TYPE"];
}
// This is Delgate Method to get selceted product
-(void) getSelectedTurftype:(NSString*) getTurftype {
self.gotTurftype = getTurftype;
NSLog(#"self.gotTurftype %#", self.gotTurftype);
[self loadProductComponentValues];
if ([_turftypePopover isPopoverVisible]) {
[_turftypePopover dismissPopoverAnimated:YES];
}
}
-(void) initAllTheProduct {
_getProductType = [NSString stringWithString:AllProduct];
self.gotTurftype = nil;
// init the segment button value
[productTypeSelector setSelectedSegmentIndex:0];
[self loadProductComponentValues];
// Check Point
[TestFlight passCheckpoint:#"SET_ALL_PRODUCT"];
}
- (IBAction)setAllProduct:(id)sender {
[self initAllTheProduct];
}
// This Method use for Load Value of ProductComponent
- (NSMutableArray*) loadProductComponentValues {
[self.resultProduct removeAllObjects];
if (!_dbObject) [self loadDBAccessDatabase];
self.resultProduct = [[NSMutableArray alloc] initWithArray:[self.dbObject getRelatedProductArray:self.gotTurftype andProductType:_getProductType]];
[_productTableView reloadData];
return self.resultProduct;
}
- (NSMutableArray *) loadProductComponentValuesIfEmpty {
// NSLog(#"%s", __FUNCTION__);
[self initAllTheProduct];
if (!_dbObject) [self loadDBAccessDatabase];
if (!self.resultProduct || ![self.resultProduct count]) self.resultProduct = [[NSMutableArray alloc] initWithArray:[self.dbObject getRelatedProductArray:self.gotTurftype andProductType:_getProductType]];
// Check Point
[TestFlight passCheckpoint:#"LOAD_DATABASE"];
return self.resultProduct;
}
- (DBAccess *) loadDBAccessDatabase {
// NSLog(#"%s", __FUNCTION__);
if (!_dbObject) {
NSString * _dbFileName = #"turfnutritiontool.db";
_dbObject = [[DBAccess alloc] initWithSSDBAccessFilename:_dbFileName];
}
return _dbObject;
}
#end
Prefer using property accessors to directly accessing instance variables in methods other than init... and dealloc. For example, there are a number of places where your code is currently doing things like this:
_getProductType = [NSString stringWithString:AllProduct];
Leaving aside that getProductType is a silly name for a property (which goes double for the instance variable, not to mention that the synthesized setter method name would be setGetProductType), this code directly assigns an object to an instance variable without taking ownership of the object. Don't do this. Instead, do one of the following:
// First let's rename your property. In the .h file, modify the current declaration like so:
#property (nonatomic, copy) NSString *productType;
// In the .m file, change the #synthesize statement:
#synthesize productType = _productType;
// In cleaning up any compiler errors/warnings from references to the old names,
// modify code that directly assigns to the instance variable (other than in `dealloc`):
// So change this:
_getProductType = [NSString stringWithString:AllProduct];
// to the following:
self.productType = [NSString stringWithString:AllProduct];
// ...or better yet:
self.productType = AllProduct;
// Note that the above statement is equivalent to the following:
[self setProductType:AllProduct];
EDIT
Also as #samfisher correctly points out, don't set ivars to nil before sending them release messages in dealloc.
use:
self._getProductType = [[NSString alloc] initWithString:AllProduct];
change this sequence:
[_getProductType release];
[_productTableView release];
[_productTypeSelector release];
[_turftypePopover release];
[_gotTurftype release];
[_resultProduct release];
[_productTableCellStyle release];
_productTableView = nil;
_productTypeSelector = nil;
_turftypePopover = nil;
_gotTurftype = nil;
_resultProduct = nil;
_productTableCellStyle = nil;
_getProductType = nil;
you were leaking memory as setting pointers to nil, //memory leak
first you should release then set pointers to nil;// no leak
When _getProductType is allocated on this line
_getProductType = [[NSString alloc] initWithString:AllProduct];
it is not retained in any way.
and as soon as _getProductType goes out of scope (which is after viewDidLoad finishes) you will not be able to reference a valid object.
so every time you reference _getProductType outside of viewDidLoad it will be as if 'released'.
Your dealloc method releases it correctly so all you have to do is add a 'retain' after allocation/initialisation, thus:
_getProductType = [[[NSString alloc] initWithString:AllProduct] retain];
However, it might be a really good idea to study properties and how they work, how they can be set up to do things like retaining or copying data as and when it is initialised. Your starting point is here.

UIScrollView with pages enabled and device rotation/orientation changes (MADNESS)

I'm having a hard time getting this right.
I've got a UIScrollView, with paging enabled. It is managed by a view controller (MainViewController) and each page is managed by a PageViewController, its view added as a subview of the scrollView at the proper offset. Scrolling is left-right, for standard orientation iPhone app. Works well. Basically exactly like the sample provided by Apple and also like the Weather app provided with the iPhone.
However, when I try to support other orientations, things don't work very well. I've supported every orientation in both MainViewController and PageViewController with this method:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
However, when I rotate the device, my pages become quite skewed, and there are lots of drawing glitches, especially if only some of the pages have been loaded, then I rotate, then scroll more, etc... Very messy.
I've told my views to support auto-resizing with
theView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
But to no avail. It seems to just stretch and distort my views.
In my MainViewController, I added this line in an attempt to resize all my pages' views:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * ([self.viewControllers count]), self.scrollView.frame.size.height);
for (int i = 0; i < [self.viewControllers count]; i++) {
PageViewController *controller = [self.viewControllers objectAtIndex:i];
if ((NSNull *)controller == [NSNull null])
continue;
NSLog(#"Changing frame: %d", i);
CGRect frame = self.scrollView.frame;
frame.origin.x = frame.size.width * i;
frame.origin.y = 0;
controller.view.frame = frame;
}
}
But it didn't help too much (because I lazily load the views, so not all of them are necessarily loaded when this executes).
Is there any way to solve this problem?
I have successfully achieved this using below method:
.h file code:
#interface ScrollViewController2 : UIViewController <UIWebViewDelegate, UIScrollViewDelegate> {
NSMutableArray *views;
int currentPage;
IBOutlet UIScrollView *scrollView;
BOOL bolPageControlUsed;
int intCurrIndex;
NSMutableArray *arrayContentData;
NSMutableArray *viewControllers;
}
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
#property (nonatomic, retain) NSMutableArray *arrayContentData;
#property (nonatomic, retain) NSMutableArray *viewControllers;
#property (nonatomic) BOOL bolPageControlUsed;
#property (nonatomic) int intCurrIndex;
-(void)bindPages;
- (void)setUpScrollView;
- (void)alignSubviews;
- (NSURLRequest *)getPageFromDocumentsDirectory:(NSString *)pstrPageName;
-(void)initiateScrollView;
-(void)loadScrollViewWithPage:(int)page;
============================================================================================
.m file
#synthesize scrollView;
#synthesize arrayContentData, viewControllers, bolPageControlUsed, intCurrIndex;
- (void)viewDidLoad {
[super viewDidLoad];
[self bindPages];
//[self setUpScrollView];
[self initiateScrollView];
}
#pragma mark -
#pragma mark Bind Pages
-(void)bindPages{
self.arrayContentData = [[NSMutableArray alloc] init];
[self.arrayContentData addObject:#"1.html"];
[self.arrayContentData addObject:#"2.html"];
[self.arrayContentData addObject:#"3.html"];
[self.arrayContentData addObject:#"4.html"];
[self.arrayContentData addObject:#"5.html"];
[self.arrayContentData addObject:#"6.html"];
[self.arrayContentData addObject:#"1.html"];
[self.arrayContentData addObject:#"2.html"];
[self.arrayContentData addObject:#"3.html"];
[self.arrayContentData addObject:#"4.html"];
[self.arrayContentData addObject:#"5.html"];
[self.arrayContentData addObject:#"6.html"];
[self.arrayContentData addObject:#"1.html"];
[self.arrayContentData addObject:#"2.html"];
[self.arrayContentData addObject:#"3.html"];
[self.arrayContentData addObject:#"4.html"];
[self.arrayContentData addObject:#"5.html"];
[self.arrayContentData addObject:#"6.html"];
[self.arrayContentData addObject:#"1.html"];
[self.arrayContentData addObject:#"2.html"];
[self.arrayContentData addObject:#"3.html"];
[self.arrayContentData addObject:#"4.html"];
[self.arrayContentData addObject:#"5.html"];
[self.arrayContentData addObject:#"6.html"];
}
#pragma mark -
#pragma mark Get Filename from Document Directory
- (NSURLRequest *)getPageFromDocumentsDirectory:(NSString *)pstrPageName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
NSString *yourFilePath = [NSString stringWithFormat:#"%#/Html/%#", documentDirectory, pstrPageName];
NSURL *url = [NSURL fileURLWithPath:yourFilePath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
return requestObj;
}
#pragma mark -
#pragma mark ScrollView Methods
-(void)initiateScrollView{
views = [[NSMutableArray alloc] initWithCapacity:[self.arrayContentData count]];
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < [self.arrayContentData count]; i++) {
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
scrollView.contentSize = CGSizeMake([self.arrayContentData count]*scrollView.bounds.size.width,
scrollView.bounds.size.height);
scrollView.delegate = self;
if(self.intCurrIndex == 0){
[self loadScrollViewWithPage:self.intCurrIndex];
}
}
-(void)loadScrollViewWithPage:(int)page{
if (page < 0) return;
if (page >= [self.arrayContentData count]) return;
// replace the placeholder if necessary
NSString *strContentName = [self.arrayContentData objectAtIndex:page];
//UIImageView *controller = [viewControllers objectAtIndex:page];
UIWebView *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null]) {
UIView *v = [[UIView alloc] initWithFrame:scrollView.bounds];
v.backgroundColor = [UIColor colorWithHue:arc4random()/(float)0x100000000
saturation:0.75
brightness:1.0
alpha:1.0];
controller = [[UIWebView alloc] initWithFrame:v.bounds];
controller.delegate = self;
controller.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
controller.center = CGPointMake(v.bounds.size.width/2, v.bounds.size.height/2);
[controller loadRequest:[self getPageFromDocumentsDirectory:strContentName]];
[v addSubview:controller];
[controller release];
[scrollView addSubview:v];
[views addObject:v];
[viewControllers replaceObjectAtIndex:page withObject:controller];
[v release];
}
[self alignSubviews];
/*
// add the controller's view to the scroll view
if (nil == controller.superview) {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
//frame.origin.y = 0;
controller.frame = frame;
[scrollView addSubview:controller];
}*/
}
-(void)scrollViewDidScroll:(UIScrollView *)sender{
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
if (self.bolPageControlUsed) {
// do nothing - the scroll was initiated from the page control, not the user dragging
return;
}
// Switch the indicator when more than 50% of the previous/next page is visible
currentPage = scrollView.contentOffset.x / scrollView.bounds.size.width;
[self loadScrollViewWithPage:currentPage];
}
// At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
self.bolPageControlUsed = NO;
}
#pragma mark -
#pragma mark setUp ScrollView
- (void)setUpScrollView {
// Set up some colorful content views
views = [[NSMutableArray alloc] initWithCapacity:[self.arrayContentData count]];
for (int i = 0; i < [self.arrayContentData count]; i++) {
UIView *v = [[UIView alloc] initWithFrame:scrollView.bounds];
v.backgroundColor = [UIColor colorWithHue:arc4random()/(float)0x100000000
saturation:0.75
brightness:1.0
alpha:1.0];
NSString *strContentName = [self.arrayContentData objectAtIndex:i];
UIWebView *controller = [[UIWebView alloc] initWithFrame:v.bounds];
controller.delegate = self;
controller.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
controller.center = CGPointMake(v.bounds.size.width/2, v.bounds.size.height/2);
[controller loadRequest:[self getPageFromDocumentsDirectory:strContentName]];
[v addSubview:controller];
[controller release];
[scrollView addSubview:v];
[views addObject:v];
[v release];
}
[self alignSubviews];
[scrollView flashScrollIndicators];
}
#pragma mark -
#pragma mark Align Scroll Subviews
- (void)alignSubviews {
// Position all the content views at their respective page positions
scrollView.contentSize = CGSizeMake([self.arrayContentData count]*scrollView.bounds.size.width,
scrollView.bounds.size.height);
NSUInteger i = 0;
for (UIView *v in views) {
v.frame = CGRectMake(i * scrollView.bounds.size.width, 0,
scrollView.bounds.size.width, scrollView.bounds.size.height);
for (UIWebView *w in v.subviews) {
[w setFrame:v.bounds];
}
i++;
}
}
#pragma mark -
#pragma mark UIWebView delegate
- (void)webViewDidStartLoad:(UIWebView *)webView {
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
}
#pragma mark -
#pragma mark Orientation
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return YES;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
currentPage = scrollView.contentOffset.x / scrollView.bounds.size.width;
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
duration:(NSTimeInterval)duration {
[self alignSubviews];
//NSLog(#"%f", currentPage * scrollView.bounds.size.width);
scrollView.contentOffset = CGPointMake(currentPage * scrollView.bounds.size.width, 0);
}
I hope, it will be helpful to all.
Cheers.
Is it necessary to have a separate UIViewController (PageViewController) for every page in your UIScrollView? Why not let your MainViewController take care of this.
Resizing your views (and your UI in general) after rotating the device is much easier when you build your UI in Interface Builder.
I'm not absolutely sure I understand you right.. however, some thoughts:
The frame property is one thing (A), how the view contents are displayed in there is another (B). The frame CGRect is the (theoretical) boundary of your view in the superview (parent view) .. however, your View does not necessarily need to fill that whole frame area.
Regarding (A):
Here we have the UIView's autoresizingMask property to set how the frame is resized when the superview is resized. Which happens when you change the orientation. However, you can usually rely on the default settings (worked for me so far).
Regarding (B):
How the view contents are distributet in the view frame is specified by UIView's property contentMode. With this property, you can set that the aspect ratio needs to stay intact. Set it to UIViewContentModeScaleAspectFit for example, or something else..
see here:
http://developer.apple.com/iphone/library/documentation/UIKit/Reference/UIView_Class/UIView/UIView.html#//apple_ref/doc/uid/TP40006816-CH3-SW99
PS: I wrote "theoretical", because your view contents may also exceed those frame boundaries - they are only limiting the view when UIView's clipsToBounds property is set to YES. I think it's a mistake that Apple set this to NO by default.
In addition to what Efrain wrote, note that the frame property IS NOT VALID if the view transform is other than the identity transform -- i.e., when the view is rotated.
Of course, you accounted for the fact that your views need to be at a new offset position, right?