ios: <Error>: CGAffineTransformInvert: singular matrix - ios

Any reason for this error "CGAffineTransformInvert"
Should I be worried?
I have a .xib with a view, and 4 webViews located outside of the view but within the same xib. Then in the code I add the webViews as subviews to a scroll view inside the view. Would that cause the problem?
Code is below:
//Called first to initialize this class. Also, initializes the nib file and tab bar name.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"More", #"More");
self.tabBarItem.image = [UIImage imageNamed:#"first"];
}
return self;
}
//Initialize the more tab titles and views
-(void)initViewsandTitles{
MoreTabPages = [NSArray arrayWithObjects:self.aboutWebView,
self.newsUpdateWebView,
self.feedbackWebView,
self.creditsResourceWebView, nil];
titles = [[NSArray alloc] initWithObjects:#"About Locavore",
#"News and Updates",
#"Feedback",
#"Credits and Resources", nil];
}
//Initialize the URLs
-(void)initURLs{
websites = [[NSArray alloc] initWithObjects:#"http://www.getlocavore.com/",
#"http://twitter.com/enjoy_locavore",
#"https://getsatisfaction.com/localdirt/products/localdirt_locavore",
#"http://www.getlocavore.com/about", nil];
}
//Called after the controller's view is loaded into memory.
- (void)viewDidLoad
{
[super viewDidLoad]; //Call the super class init method
[self setupSpinner]; //Start the spinner animatio
[self initViewsandTitles]; //Initialize the views and titles
[self initURLs]; //Initialize the URLs
[self setScrollandPageViewProperties]; //Set the scroll and page view properties
[self setUpPageViews]; //Create the web pages
}
//UIScrollViewDelegate Protocol Reference. Called whn the user scrolls the content within the reciever
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if (!pageControlBeingUsed) {
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.MoreTabScrollView.frame.size.width;
int page = floor((self.MoreTabScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.MoreTabPageControl.currentPage = page;
self.MoreTabTitle.text = [titles objectAtIndex:page];
}
}
//UIScrollViewDelegate Protocol Reference. Called when the scroll view is about to start scolling content
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
pageControlBeingUsed = NO;
}
//UIScrollViewDelegate Protocol Reference. Called when the scroll view has ended decelerating the scrolling movement
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSLog(#"DID END SCROLLING");
pageControlBeingUsed = NO;
}
//Called when the page control value changes
- (IBAction)MoreTabChangePage {
// Update the scroll view to the appropriate page
CGRect frame;
frame.origin.x = self.MoreTabScrollView.frame.size.width * self.MoreTabPageControl.currentPage;
frame.origin.y = 0;
frame.size = self.MoreTabScrollView.frame.size;
[self.MoreTabScrollView scrollRectToVisible:frame animated:YES];
self.MoreTabTitle.text = [titles objectAtIndex:self.MoreTabPageControl.currentPage];
// Keep track of when scrolls happen in response to the page control
// value changing. If we don't do this, a noticeable "flashing" occurs
// as the the scroll delegate will temporarily switch back the page
// number.
pageControlBeingUsed=YES;
}
//Create a frame for each page and add the page to the scroll view
-(void)setUpPageViews{
//Set up all page views for the more tab
for (int i = 0; i < MoreTabPages.count; i++) {
//Get the current table view controller page
UIWebView *webController= [MoreTabPages objectAtIndex:i];
//Request the URL and load the request
NSURL *urll =[NSURL URLWithString:[websites objectAtIndex:i]];
//Run requests in seperate thread
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
NSURLRequest *firstReq = [NSURLRequest requestWithURL:urll];
[webController loadRequest:firstReq];
dispatch_sync(dispatch_get_main_queue(), ^{
//Create a frame for the current table view controller
CGRect frame = webController.frame;
frame.origin.x = self.MoreTabScrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.MoreTabScrollView.frame.size;
webController.frame = frame;
//Add the the current table view controller page to the scroll view
[self.MoreTabScrollView addSubview:webController];
//Release the controller object it is no longer needed
[webController release];
if(i == 3){
[spinner stopAnimating];
}
});
});
}
}
//Set al the properties for the scroll view and page controll
-(void)setScrollandPageViewProperties{
self.MoreTabScrollView.contentSize = CGSizeMake(self.MoreTabScrollView.frame.size.width * MoreTabPages.count,
self.MoreTabScrollView.frame.size.height);
self.MoreTabScrollView.scrollsToTop = NO;
self.MoreTabScrollView.contentOffset = CGPointMake(self.MoreTabScrollView.frame.size.width, 0);
self.MoreTabPageControl.numberOfPages = MoreTabPages.count;
}
-(void)setupSpinner{
spinner.hidesWhenStopped = YES;
[spinner startAnimating];
}
//Called if the application receives a memory warning
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//Called when the UIViewController's reference count goes to zero
- (void)dealloc {
[super dealloc];
[MoreTabPageControl release];
[MoreTabScrollView release];
[MoreTabTitle release];
[MoreTabPages release];
[titles release];
[websites release];
[spinner release];
}
#end

try setting the minimum zoom scale for your each webview.
[self.aboutWebView.scrollView setMinimumZoomScale:0.1]
it will throw the same error if the scrollview reaches zero at zero zoom.

This may happen with affine transformations when you're scaling UIScrollView instance to 0 either using setZoomScale:animated: method or zoomScale property, so please check your scroll views.
Make sure your zoomScale, minimumZoomScale and maximumZoomScale to set to at least 0.1.
Related:
Calculating minimumZoomScale of a UIScrollView
UIScrollView not respecting minimumZoomScale after changing the subview

Related

Present a loading view that blocks touches

I'm trying to add a subview to view that displays an activity indicator and blocks touches while I'm fetching data from the server.
Here is the code that adds the loading view to the main view controller's screen:
+ (void)showLoadingView {
ViewController *vc = [AppDelegate mainViewController];
if (!vc._activityViewContainer) {
LoadingView *loadingView = [[LoadingView alloc] initWithFrame:vc.view.bounds];
[vc.view addSubview:loadingView];
vc._activityViewContainer = loadingView;
}
}
+ (void)stopLoadingView {
ViewController *vc = [AppDelegate mainViewController];
if (vc._activityViewContainer) {
[vc._activityViewContainer removeFromSuperview];
vc._activityViewContainer = nil;
}
}
Here is my loading view:
#implementation LoadingView
- (id)initWithFrame:(CGRect)frame {
if (self == [super initWithFrame:frame]) {
self.userInteractionEnabled = YES;
self.backgroundColor = [UIColor lightGrayColor];
self.alpha = 0.6;
self.layer.zPosition = 10000;
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
NSUInteger avSize = 100;
CGRect activityViewFrame = CGRectMake((frame.size.width - avSize) / 2, (frame.size.height - avSize) / 2, avSize, avSize);
activityView.frame = activityViewFrame;
[self addSubview:activityView];
[activityView startAnimating];
}
return self;
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return [self pointInside:point withEvent:event] ? self : nil; }
#end
I'm trying to make it so that the loading view absorbs/blocks all touches to other sibling views. It's working fine when I'm testing it by presenting it without doing any fetching, it enters the loading view's hitTest method and blocks the touch. However, when I'm actually doing any kind of fetch from the server, it doesn't seem to work. The touch is delayed a few seconds and does not get intercepted by the LoadingView.
I'm using GTMHTTPFetcher's
- (BOOL)beginFetchWithCompletionHandler:(void (^)(NSData *data, NSError *error))handler
I'm not that sure what's going on and I tried looking for similar examples on SO, but couldn't find what I was looking for. Any help would be great, thanks!
I was doing my fetches on the main thread which was blocking the UI; I thought GTM did everything on a different thread, but it doesn't. Thanks to those who posted things which helped me in the right direction

Attempting to incorporate apple's page control example into a storyboard viewcontroller

I have some images I'm trying to load within a scroll view similar to apple's page control example. My app crashes with an error of
'NSInvalidArgumentException', reason: '-[TutorialViewController
loadScrollViewWithPage:]: unrecognized selector sent to instance
0x687d0b0'
I think I understand enough of this that it's telling me that I don't have a method for the selector... but I'm not sure how to fix it! Thank you in advance.
Header File
//TutorialViewController.h
#import
#interface TutorialViewController : UIViewController <UIScrollViewDelegate>
{
// To be used when scrolls originate from the UIPageControl
BOOL pageControlUsed;
int pageNumber;
}
#property (nonatomic, retain) NSArray *iPhoneTutorial;
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
#property (nonatomic, retain) IBOutlet UIPageControl *pageControl;
#property (nonatomic, retain) NSMutableArray *viewControllers;
- (IBAction)changePage:(id)sender;
#end
Implementation File
//TutorialViewController.m
#import "TutorialViewController.h"
static NSUInteger kNumberOfPages = 3;
static NSString *NameKey = #"nameKey";
static NSString *ImageKey = #"imageKey";
#interface TutorialViewController (PrivateMethods)
- (void)loadScrollViewWithPage:(int)page;
- (void)scrollViewDidScroll:(UIScrollView *)sender;
#end
#implementation TutorialViewController
#synthesize scrollView, pageControl;
- (void)awakeFromNib
{
// load our data from a plist file inside our app bundle
NSString *path = [[NSBundle mainBundle] pathForResource:#"iPhoneTutorial" ofType:#"plist"];
self.iPhoneTutorial = [NSArray arrayWithContentsOfFile:path];
// view controllers are created lazily
// in the meantime, load the array with placeholders which will be replaced on demand
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++)
{
[controllers addObject:[NSNull null]];
}
//self.viewControllers = controllers;
//[controllers release];
// a page is the width of the scroll view
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = NO;
scrollView.delegate = self;
pageControl.numberOfPages = kNumberOfPages;
pageControl.currentPage = 0;
// pages are created on demand
// load the visible page
// load the page on either side to avoid flashes when the user starts scrolling
//
[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];
}
// load the view nib and initialize the pageNumber ivar
- (id)initWithPageNumber:(int)page
{
pageNumber = page;
return self;
}
- (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 (pageControlUsed)
{
// 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
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// A possible optimization would be to unload the views+controllers which are no longer visible
}
// At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
pageControlUsed = NO;
}
// At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
pageControlUsed = NO;
}
- (IBAction)changePage:(id)sender
{
int page = pageControl.currentPage;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// update the scroll view to the appropriate page
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
// Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
pageControlUsed = YES;
}
- (void)viewDidLoad
{
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
You have to add an
- (void)loadScrollViewWithPage:(int)page
method where you add your view
like
switch(page) {
case 0:
myView1 = [[MyView1ViewController alloc] initWithNibName:#"MyView1ViewController" bundle:nil];
[scrollView addSubview: myViewPage1.view];
break;
}
But the Apple Demo "PageControl" has such a method in File PhoneContentViewController.m

UIScrollView doesn't release images

I have a UIScrollView that shows a gallery of images from a plist file.
I also have a function to delete an image from the gallery image list that basically deletes an object in the plist file and then reload the images in the ScrollView.
The issue is I am not able to release the images of the UIScrollView before to reload it with the new content when I use the method - (IBAction)deleteimage:(id)sender. The new content is loaded but over the older content and then the images are still behind the new one.
What I should do to release images before to reload the scrollview content?
The code I am using is :
#import "ImageScrollViewController.h"
#interface ImageScrollViewController ()
#end
#implementation ImageScrollViewController
#synthesize images,scrollView,pageControl,subview;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
scrollView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
[self setupthescroll];
self.pageControl.currentPage = 0;
}
- (void)setupthescroll{
//Get the images of the Array
NSUserDefaults *success = [NSUserDefaults standardUserDefaults];
images = [success mutableArrayValueForKey:#"imagelist"];
NSLog(#"list of images%#",images);
pageControlBeingUsed = NO;
for (int i = 0; i < images.count; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
subview = [[UIImageView alloc] initWithFrame:frame];
NSString *str4 = [images objectAtIndex:i];
subview.image = [[[UIImage alloc] initWithContentsOfFile:str4] autorelease];
self.subview.contentMode = UIViewContentModeScaleAspectFit;
[self.scrollView addSubview:subview];
[subview release];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * images.count, self.scrollView.frame.size.height);
self.pageControl.numberOfPages = images.count;
//Get the number of the images
int page;
page = self.pageControl.currentPage;
printf("Current Page: %d", page);
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if (!pageControlBeingUsed) {
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.scrollView.frame.size.width;
int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.pageControl.currentPage = page;
}
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
pageControlBeingUsed = NO;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
pageControlBeingUsed = NO;
}
- (IBAction)changePage {
// Update the scroll view to the appropriate page
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * self.pageControl.currentPage;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
[self.scrollView scrollRectToVisible:frame animated:YES];
pageControlBeingUsed = YES;
}
- (IBAction)deleteimage:(id)sender{
//Get the number of the image
int page;
page = self.pageControl.currentPage;
printf("Current Page: %d", page);
//Remove the images of the Array
NSUserDefaults *success = [NSUserDefaults standardUserDefaults];
images = [success mutableArrayValueForKey:#"imagelist"];
[images removeObjectAtIndex:page];
NSLog(#"list of images%#",images);
//Update the Array
NSUserDefaults *arrayofimages = [NSUserDefaults standardUserDefaults];
[arrayofimages setObject:images forKey:#"imagelist"];
//Refresh the ScrollView
[self setupthescroll];
//post the notification than images have been updated
NSUserDefaults *deleted = [NSUserDefaults standardUserDefaults];
[deleted setObject:#"deleted" forKey:#"deletedimages"];
}
- (IBAction)closepage:(id)sender{
[self dismissModalViewControllerAnimated:YES];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
[pageControl release];
[scrollView release];
//[images release];
[super dealloc];
}
#end
If you are reloading the entire scrollview (i.e. adding all the images back), you first need to remove the existing images.
Use UIView's removeFromSuperview method to remove views from the scrollview.
So a code snippet to remove all image views from the scrollview would look something like this
NSArray *imgViews = [scrollView subviews];
for(id aView in imgViews){
if([aView isKindOfClass:[UIImageView class]]){
[aView removeFromSuperview]; //remove only if its an imageview
}
}
If you already have reference to the image views, you can directly call the method on them without iterating through all subviews of the scrollview.
You should remove all the UIImageView within the scrollView.
something like
NSArray* subviews = [[scrollview subviews] copy];
for (UIView* v in subviews) {
[v removeFromSuperview];
}
[subviews release];
You forgot to remove the previous image views from the scrollView subviews. A brutal method to to this (at least for testing the hypothesis) would be to add the following line at the beginning of setupthescroll:
[self.scrollView.subviews makeObjectsPerfomSelector:#selector(removeFromSuperview)];
The problem with this would be that the scrollview's private subviews ( scrollers, for instance ) would be removed too.
So in practice you should keep track of the subviews you created in an ivar array, and perform the above line on this array instead of the subviews array, and clear the array afterwards.
Alternatively, a much cleaner method would be to delete only the subview corresponding to the deleted image, and to update the frames of the remaining image views, instead of deleting and recreating everything. You could use a dictionary or the subviews tag property to keep track of wich view is associated to which image.

Several Questions about ScrollView with PageControl

I am pretty new to iOS development and I stumbled upon several issues for which I couldn't easily find any answers yet:
General Setup: I'm using a ScrollView with PageControl inside a TabBarApplication
Is it possible to have the PageControl within the same area as the content of the pages? For me it always gets hidden by the SrollView's Views, but due to display space being rare I really need it on the same height as the actual content.
I've fooled around in some Sandbox-Project and whenever I first started to implement a button into the View of a ScrollView-Page the Pages of the ScrollView wouldn't show immediately anymore, but only after the first scroll attempt. I'd post some code about that but its basically only autogenerated from IB.
This is a general Question about possibilities again: The main design of the Project should be a TabBarApplication with a NavigationController letting you go deeper into sub-menues like it is pretty common. Now in one of the Tabs there should be the PageControl, in which you can then again go into sub-menues by pushing Views on a NavigationController stack . Is this possible?
Some Code for 2.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++) {
[controllers addObject:[NSNull null]]; // [TaskPageViewController new]];
}
self.viewControllers = controllers;
[controllers release];
// a page is the width of the scroll view
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = NO;
scrollView.delegate = self;
pageControl.numberOfPages = kNumberOfPages;
pageControl.currentPage = 0;
}
- (IBAction)changePage:(id)sender {
int page = pageControl.currentPage;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// update the scroll view to the appropriate page
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
// Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
pageControlUsed = YES;
}
- (void)loadScrollViewWithPage:(int)page {
if (page < 0) return;
if (page >= kNumberOfPages) return;
// replace the placeholder if necessary
TaskPageViewController *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null]) {
controller = [[TaskPageViewController alloc] init]; //WithPageNumber:page];
[viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
// add the controller's view to the scroll view
if (nil == controller.view.superview) {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
- (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 (pageControlUsed) {
// 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
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// A possible optimization would be to unload the views+controllers which are no longer visible
}
You can have two view hierarchies for this:
Have the page control inside scrollview with origin fixed at contentOffset property
Have the page control in the superview of scrollView, but at a higher index (i.e. floating above it)
This depends on where you put the code of adding the subviews. Is it in the delegate method of scrollView? viewDidLoad? Somewhere else? Some code might help.
Not sure why you'd need to have a page control when it's a drill-down navigation. Pages are for navigating same level items.

Photo Viewer iPad & iPhone

I've long been trying to make an image viewer, but really I do not what does not work.
Here's a picture like you should get!
This is UIScrollView. The UIImage add to UIScrollView. When user scroll - image must download to UIImageView. I think we need download image in a separate thread. For this I am using - NSOperationqueue and NSInvocationOperation.
This is my code.
In delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
MyThumbnailsBook * myThumbnailsBook = [[MyThumbnailsBook alloc] initWithFrame:CGRectMake(0, 20, 768, 1004)];
[myThumbnailsBook createThumbnails];
[myThumbnailsBook setContentSize:CGSizeMake(768, 1004 * 10)];
[myThumbnailsBook setBackgroundColor:[UIColor blackColor]];
[self.window addSubview:myThumbnailsBook];
[self.window makeKeyAndVisible];
return YES;
}
In class inherit UIScrollView MyThumbnailsBook.m
#define COUNT 100
#import "MyThumbnailsBook.h"
#import "MyImageDownload.h"
#implementation MyThumbnailsBook
#pragma mark -
#pragma mark Initialization & Create Thumbnails
- (id)initWithFrame:(CGRect)frame{
if((self = [super initWithFrame:frame])){
self.delegate = self;
}
return self;
}
- (void)createThumbnails{
float point_x = 20;
float point_y = 20;
for(NSInteger i = 0; i < COUNT; i++){
if(i%3==0 && i != 0){
point_x = 20;
point_y += 220;
}
// Create new image view.
NSURL * url = [[NSURL alloc] initWithString:#"http://storage.casinotv.com/videos/SOYCL/pages/P68.jpg"];
MyImageDownload * imageDownload = [[MyImageDownload alloc] initWithImageURL:url];
[imageDownload setFrame:CGRectMake(point_x, point_y, 200, 200)];
[self addSubview:imageDownload];
[imageDownload release];
[url release];
point_x += 220;
}
}
#pragma mark -
#pragma mark Scroll View Protocol
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
// If scroll view no decelerating.
if(!decelerate){
[self asyncImageDownload];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
[self asyncImageDownload];
}
#pragma mark -
#pragma mark Download Image
// If scroll stopped - download image to thumbnails.
- (void)asyncImageDownload{
}
#end
In class inherit UIScrollView MyImageDownload.m
#import "MyImageDownload.h"
#implementation MyImageDownload
// This is init method. When class init - we add new operation for download image.
- (id)initWithImageURL:(NSURL*)url{
if((self == [super init])){
[self setBackgroundColor:[UIColor yellowColor]];
NSArray * params = [NSArray arrayWithObjects:url, nil];
queue = [[NSOperationQueue alloc] init];
[queue setMaxConcurrentOperationCount:1];
NSInvocationOperation* operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(asyncDownload:) object:params];
[queue addOperation:operation];
[params release];
}
return self;
}
// Download image to data and after to self (UIImageView).
- (void)asyncDownload:(NSArray *)params{
NSData * data = [NSData dataWithContentsOfURL:[params objectAtIndex:0]]; // Get image data with url.
if(data) [self setImage:[UIImage imageWithData:data]];
[data release];
}
#end
In this example, the images are not loaded and I do not understand why?
I have always used these classes in which the images were loaded from the internet, but I also had problems with memory and I do not know too how to solve it. For example, when to scroll images I get exception - Received memory warning. Level=1 & 2 and after app crash. And I have no idea what to do. I understand what you need as a separate download of images over time and to remove non visible objects but I have found I need the algorithm.
For example - when i go to scrollDidScroll method i get all object when i not see them and remove image:
NSArray *views = [self subviews];
for (UIImageView *v in views) {
if(v.frame.origin.y >= self.contentOffset.y && v.frame.origin.y <= self.contentOffset.y + self.frame.size.height){
// If image of imageview is equal nil - call new operation
if(v.image == nil){
[self requestImageForIndexPath:[NSNumber numberWithInt:v.tag]];
}
else
{
v.image = nil;
}
}
}
self - this is class inherit UIScrollView.
I was confused and ask for help in resolving this issue. TNX all!
The Three20 library includes this functionality in the form of TTPhotoViewController.

Resources