NSOperationQueue Calling performSelectorOnMainThread crashes the application - multithreading

I'm using the following code to download some pic from the server,
-(void)viewDidLoad
{
for (int i = 0 ; i < picsNames.count ; i++) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(i * 320.0, 0.0, 320.0, self.view.frame.size.height)];
imageView.backgroundColor = [UIColor blackColor];
imageView.tag = IMAGE_VIEWS_TAG + i;
[scrollView addSubview:imageView];
//getting the image
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(getImage:) object:imageView];
[queue addOperation:operation];
}
}
-(void)getImage:(UIImageView *)imageView
{
//getting the "image" from the server .....
[self performSelectorOnMainThread:#selector(loadPic:) withObject:[NSArray arrayWithObjects:imageView, image,nil] waitUntilDone:YES];
}
-(void)loadPic:(NSArray *)imageAndImageViewArray
{
//loading the image to imageview
UIImageView *imageView = (UIImageView *)[imageAndImageViewArray objectAtIndex:0];
imageView.image = (UIImage *)[imageAndImageViewArray objectAtIndex:1];
}
After loading some pictures the following line gives memory warning and crashes the app.
[self performSelectorOnMainThread:#selector(loadPic:) withObject:[NSArray arrayWithObjects:imageView, image,nil] waitUntilDone:YES];
I don't know how to solve this issue.
Thanks everyone :)

So after spending too much time on this I realized that the error is due to having too many UIImage objects alloc at the same time no the NSQueue of main NSTread.
So Just changed to code so I have only 10 UIImage objects at the time.

Related

Why is shouldStartLoadWithRequest only being invoked the first time through?

I'm trying to display a list of web pages the user can switch between in my app. I've done this successfully with documents. however, I don't want the user to be able to navigate from these pages. I found out how to do this by looking it up. The problem is that it only executes on the first page. When I switch to another page shouldStartLoadWithRequest stops working even when I go back to the first page. (This is all done with my specially designed back and forward buttons.) How can I fix this so that it will be invoked every single time and prevent the user from clicking links and navigating away from my set pages? I'm new to objective-c. All the relevant code is below. Some things were declared globally in the .h. Sorry it's kind of rough. I tabbed over only what was needed to make it into code formatting. Thanks!
My .h file:
#import <UIKit/UIKit.h>
#interface learnViewController : UIViewController <UINavigationControllerDelegate>
{
IBOutlet UIWebView *web;
UIButton *backButton;
UIButton *forButton;
}
#end
My .m file
#import "learnViewController.h"
#import "ViewController.h"
static NSString* links[] =
{
#"http://www.nlm.nih.gov/medlineplus/ency/article/000141.htm",
#"http://www.nlm.nih.gov/medlineplus/ency/article/000065.htm",
#"http://www.nlm.nih.gov/medlineplus/ency/article/001087.htm",
#"http://www.nlm.nih.gov/medlineplus/ency/article/000091.htm",
#"http://www.nlm.nih.gov/medlineplus/ency/article/007270.htm",
#"http://www.nlm.nih.gov/medlineplus/ency/article/000145.htm",
#"http://www.nlm.nih.gov/medlineplus/ency/article/000093.htm",
#"http://www.nlm.nih.gov/medlineplus/ency/article/000087.htm",
#"http://www.nlm.nih.gov/medlineplus/ency/article/000140.htm",
#"http://www.nlm.nih.gov/medlineplus/ency/article/000132.htm"
};
int numlinks = 10;
int i = 0;
#interface learnViewController ()
#end
#implementation learnViewController
- (void)viewDidLoad
{
[super viewDidLoad];
float viewWidth = self.view.frame.size.width;
float viewHeight = self.view.frame.size.height;
self.view.multipleTouchEnabled = true;
//Background
UIImageView *backgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, viewWidth, viewHeight)];
backgroundView.image = [UIImage imageNamed:#"Background.png"];
[self.view addSubview:backgroundView];
//Show Portal
web = [[UIWebView alloc]initWithFrame:CGRectMake(0.0, viewHeight/34.0, viewWidth, (viewHeight - viewHeight/6.4))];
self->web.delegate = self;
web.scrollView.scrollEnabled = TRUE;
web.scalesPageToFit = TRUE;
[self loadDocument:links[i] inView:web];
[self.view addSubview:web];
//Buttons
UIButton *homeButton = [[UIButton alloc] initWithFrame:CGRectMake((viewWidth/2.0 - viewWidth/6.0/2.0), (viewHeight - viewHeight*280.0/2208.0/2.0 - viewWidth/6.0/2.0), (viewWidth/6.0), (viewWidth/6.0))];
[homeButton
setBackgroundImage:[UIImage imageNamed:#"Home.png"]
forState:UIControlStateNormal];
[homeButton addTarget:self action:#selector(homePressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:homeButton];
backButton = [[UIButton alloc] initWithFrame:CGRectMake((viewWidth/2.0/3.5 - viewWidth/9.0/2.0), (viewHeight - viewHeight*280.0/2208.0/2.0 - viewWidth/9.0/2.0), (viewWidth/9.0), (viewWidth/9.0))];
[backButton
setBackgroundImage:[UIImage imageNamed:#"Back.png"]
forState:UIControlStateNormal];
backButton.enabled = FALSE;
[backButton addTarget:self
action:#selector(backPressed:)
forControlEvents:UIControlEventTouchDown];
[self.view addSubview:backButton];
forButton = [[UIButton alloc] initWithFrame:CGRectMake((viewWidth/2.0/3.5*2.0 - viewWidth/9.0/2.0), (viewHeight - viewHeight*280.0/2208.0/2.0 - viewWidth/9.0/2.0), (viewWidth/9.0), (viewWidth/9.0))];
[forButton
setBackgroundImage:[UIImage imageNamed:#"Forward.png"]
forState:UIControlStateNormal];
[forButton addTarget:self
action:#selector(forPressed:)
forControlEvents:UIControlEventTouchDown];
[self.view addSubview:forButton];
UIButton *refButton = [[UIButton alloc] initWithFrame:CGRectMake((viewWidth - viewWidth/2.0/3.5*2.0 - viewWidth/9.0/2.0), (viewHeight - viewHeight*280.0/2208.0/2.0 - viewWidth/9.0/2.0), (viewWidth/9.0), (viewWidth/9.0))];
[refButton
setBackgroundImage:[UIImage imageNamed:#"Scale.png"]
forState:UIControlStateNormal];
[refButton addTarget:self
action:#selector(refPressed:)
forControlEvents:UIControlEventTouchDown];
[self.view addSubview:refButton];
UIButton *webButton = [[UIButton alloc] initWithFrame:CGRectMake((viewWidth - viewWidth/2.0/3.5 - viewWidth/9.0/2.0), (viewHeight - viewHeight*280.0/2208.0/2.0 - viewWidth/9.0/2.0), (viewWidth/9.0), (viewWidth/9.0))];
[webButton
setBackgroundImage:[UIImage imageNamed:#"Web.png"]
forState:UIControlStateNormal];
[webButton addTarget:self
action:#selector(webPressed:)
forControlEvents:UIControlEventTouchDown];
[self.view addSubview:webButton];
}
//Button presses
-(void)homePressed:(id)sender
{
ViewController *home = [[ViewController alloc] initWithNibName:nil bundle:nil];
[self presentViewController:home animated:YES completion:NULL];
}
- (void) refPressed:(id)sender
{
[self loadDocument:links[i] inView:web];
}
-(void)backPressed:(id)sender
{
float viewWidth = self.view.frame.size.width;
float viewHeight = self.view.frame.size.height;
if (i > 0)
{
[web removeFromSuperview];
i--;
web = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, viewHeight/34.0, viewWidth, (viewHeight - viewHeight/6.4))];
[self loadDocument:links[i] inView:web];
web.scrollView.scrollEnabled = TRUE;
web.scalesPageToFit = TRUE;
[self.view addSubview:web];
forButton.enabled = TRUE;
}
if (i == 0)
{
backButton.enabled = FALSE;
}
}
-(void)forPressed:(id)sender
{
float viewWidth = self.view.frame.size.width;
float viewHeight = self.view.frame.size.height;
if (i < numlinks - 1)
{
[web removeFromSuperview];
i++;
web = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, viewHeight/34.0, viewWidth, (viewHeight - viewHeight/6.4))];
[self loadDocument:links[i] inView:web];
web.scrollView.scrollEnabled = TRUE;
web.scalesPageToFit = TRUE;
[self.view addSubview:web];
backButton.enabled = TRUE;
}
if (i == numlinks - 1)
{
forButton.enabled = FALSE;
}
}
-(void)loadDocument:(NSString*)documentName inView:(UIWebView*)webView
{
NSString *url = links[i];
NSURL *nsurl = [NSURL URLWithString:url];
NSURLRequest *nsrequest = [NSURLRequest requestWithURL:nsurl];
[webView loadRequest:nsrequest];
}
-(void)webPressed:(id)sender
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:links[i]]];
}
-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = request.URL;
NSString *urlString = url.absoluteString;
NSRange range = [urlString rangeOfString:links[i]];
if (range.location != NSNotFound)
{
return YES;
}
else
{
return NO;
}
}
- (void)viewDidUnload
{
[self->web stopLoading];
self->web.delegate = nil;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Okay, I figured it out through trial and error since no one wanted to help me. I tried looking for answers to similar questions, but nothing actually worked for me. If you're reading this and having the same problem, this is how you fix it. All you have to do is reset the web delegate to nil then back to self as so:
self.webView.delegate = nil;
self.webView.delegate = self;
I don't know why everyone else's code was so complex, and I can only speculate as to why this works. I just got lucky honestly, but I think it maybe clears the cache when you do this, thus making each page fresh to the program. That's what other people were talking about. However, their methods did not work for me either because of my lack of experience or because they do not fit my particular case. This is much simpler and is guaranteed to work as long as you make sure it does this each time you load one of your designated web pages. You're welcome if you're reading this. If anyone would so kindly as to look at my post and explain why this works in better detail, please feel free to do so!

iOS Memory leak in UIImage

I'm using ios 7 and I need to do:
In separete thread I want to create image from network and put it into UIImageView. I need to do this every 200 ms.
My code looks like:
- (void)startPreview:(CGFloat)specialFramesRates;
{
if(isPreview)
return;
[Utils runOnThread:^{
[Log log:#"Start preview"]; //here we have a leak
isPreview = YES;
while(isPreview) {
[self getNewBitmap];
sleep(fpsTime);
if(!isPreview)
break;
if(checkAvabilityCam > 10)
break;
}
[Log log:#"Stoped preview"];
}];
}
- (void)getNewBitmap
{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setTimeoutInterval:1];
[request setHTTPMethod:#"GET"];
NSError *requestError;
NSURLResponse *urlResponse = nil;
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if(delegate && response) {
checkAvabilityCam = 0;
//TODO what I should do here?
UIImage *image = [UIImage imageWithData:newImage]; //HERE IS LEAK !!!!
[delegate onShowImage:response]; //here I show image in main thread
image = nil; //With or without doesn't work
return;
}
checkAvabilityCam++;
if(delegate)
[delegate onShowDefaultImage];
}
In this line of code I have a problem:
//TODO what I should do here?
UIImage *image = [UIImage imageWithData:newImage]; //HERE IS LEAK !!!!
[delegate onShowImage:response]; //here I show image in main thread
image = nil; //With or without doesn't work
What can I use instead of "[UIImage imageWithData:]" ? I tried save into file and load but with the same effect. What should I do?
UIImage *image = [UIImage imageWithData:newImage]; //HERE IS LEAK !!!!
You are creating an autoreleased object here. Since you're doing this on a background thread, any autoreleased objects you create won't get released unless your thread has its own autorelease pool.
If you are using ARC, create an autorelease pool with the #autoreleasepool keyword:
#autoreleasepool {
UIImage *image = [UIImage imageWithData:newImage];
// Do stuff with image
}
If you're not using ARC, create an autorelease pool manually:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *image = [UIImage imageWithData:newImage];
// Do stuff with image
[pool release];

Value stored to 'image' during its initialization is never read

When running the analyze in xcode 4.2 i have the warning "Value stored to 'image' during its initialization is never read." Anyone can help me out what is wrong with the code?
UIImage *image=[[[UIImage alloc] init]autorelease];
if (carousel==recipeCarousel) {
image = [recipeItems objectAtIndex:index];
} else {
image = [packItems objectAtIndex:index];
}
UIView *view = [[[UIImageView alloc] initWithImage:image] autorelease];
return view;
Thank you.
You have alloc the UIImage with this code
UIImage *image=[[[UIImage alloc] init]autorelease];
but later you assign object in recipeItems or packItems
so that you will lose your control to the allocated object.
So you can either do this
UIImage *image = nil;
if (carousel==recipeCarousel) {
image = [recipeItems objectAtIndex:index];
} else {
image = [packItems objectAtIndex:index];
}
or
NSArray *targetItems = nil;
if (carousel==recipeCarousel) {
targetItems = recipeItems;
} else {
targetItems = packItems;
}
UIImage *image = [targetItems objectAtIndex:index];

Find assets in library - add to a AVMutableComposition - export = crash

I've been struggling with adding assets from the iPhone Photo Library to a AVMutableComposition and then export them. Here is what I got:
Finding the assets: (here I grab the AVURLAsset)
-(void) findAssets {
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
// Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos.
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
// Within the group enumeration block, filter to enumerate just videos.
[group setAssetsFilter:[ALAssetsFilter allVideos]];
[group enumerateAssetsUsingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop){
// The end of the enumeration is signaled by asset == nil.
if (alAsset) {
ALAssetRepresentation *representation = [alAsset defaultRepresentation];
NSURL *url = [representation url];
AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
// Do something interesting with the AV asset.
[thumbs addObject:alAsset];
[assets addObject:avAsset];
}else if(alAsset == nil){
[self createScroll];
}
}];
}
failureBlock: ^(NSError *error) {
// Typically you should handle an error more gracefully than this.
NSLog(#"No groups");
}];
[library release];
}
Here I add a asset to my composition (I use the first object in the array for testing only.
-(void) addToCompositionWithAsset:(AVURLAsset*)_asset{
NSError *editError = nil;
composition = [AVMutableComposition composition];
AVURLAsset* sourceAsset = [assets objectAtIndex:0];
Float64 inSeconds = 1.0;
Float64 outSeconds = 2.0;
// calculate time
CMTime inTime = CMTimeMakeWithSeconds(inSeconds, 600);
CMTime outTime = CMTimeMakeWithSeconds(outSeconds, 600);
CMTime duration = CMTimeSubtract(outTime, inTime);
CMTimeRange editRange = CMTimeRangeMake(inTime, duration);
[composition insertTimeRange:editRange ofAsset:sourceAsset atTime:composition.duration error:&editError];
if (!editError) {
CMTimeGetSeconds (composition.duration);
}
}
And finally I export the comp and here it crashes
-(void)exportComposition {
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetPassthrough];
NSLog (#"can export: %#", exportSession.supportedFileTypes);
NSArray *dirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [dirs objectAtIndex:0];
NSString *exportPath = [documentsDirectoryPath stringByAppendingPathComponent:EXPORT_NAME];
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
NSURL *exportURL = [NSURL fileURLWithPath:exportPath];
exportSession.outputURL = exportURL;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;//#"com.apple.quicktime-movie";
[exportSession exportAsynchronouslyWithCompletionHandler:^{
NSLog (#"i is in your block, exportin. status is %d",
exportSession.status);
switch (exportSession.status) {
case AVAssetExportSessionStatusFailed:
case AVAssetExportSessionStatusCompleted: {
[self performSelectorOnMainThread:#selector (exportDone:)
withObject:nil
waitUntilDone:NO];
break;
}
};
}];
}
Does anyone have an idea of what it might be? It crashes on
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetPassthrough];
And I tried different presets and outputFileTypes.
Thanks
* SOLVED *
I have to answer my own question now when I have solved. It's amazing that I've been struggling with this for a whole day and then I fix it right after posting a question :)
I changed and moved:
composition = [AVMutableComposition
composition];
to:
composition = [[AVMutableComposition
alloc] init];
I think I was too tired when I was working on this yesterday. Thanks guys!

CoverFlow multiple Views

Good Morning at all,
i have a big problem in the following code and no solution, so i hope someone could
help me:
- (IBAction)goToChart {
[rootViewController switchViews];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *weiter = [UIButton buttonWithType:UIButtonTypeRoundedRect];
weiter.frame = CGRectMake(100, 400, 120, 40);
[weiter addTarget:self action:#selector(goToChart) forControlEvents:UIControlEventTouchUpInside];
NSString *ansicht = #"Weiter";
[weiter setTitle:ansicht forState:UIControlStateNormal];
[self.view addSubview:weiter];
// loading images into the queue
loadImagesOperationQueue = [[NSOperationQueue alloc] init];
NSString *imageName;
for (int i=0; i < 10; i++) {
imageName = [[NSString alloc] initWithFormat:#"cover_%d.jpg", i];
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
UIImage *aktuellesImage = imageView.image;
UIImage *scaledImage = [aktuellesImage scaleToSize:CGSizeMake(100.0f, 100.0f)];
[(AFOpenFlowView *)self.view setImage:scaledImage forIndex:i];
[imageName release];
NSLog(#"%d is the index",i);
}
[(AFOpenFlowView *)self.view setNumberOfImages:10];
}
So you can see there 10 Images in this CoverFlowView, but how could i find out the ACTUAL picture that is in front, to use this in another view??
Could someone help me, please?
Greetings Marco
-(void)openFlowView: (AFOpenFlowView *)openFlowView imageSelected:(int)index
{
AppDelegate_iPhone *appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication]delegate];
db_detail = (DB_data *)[self.GalleryArray objectAtIndex:index];
appDelegate.Id = db_detail.Id;
// NSLog(#"id: value is %d",db_detail.Id);
// NSLog(#"Name vlaue is: %#",db_detail.Name);
appDelegate.title = db_detail.Name;
DetailMovieViewController *ViewController = [[DetailMovieViewController alloc]init];
[self.navigationController pushViewController:ViewController animated:YES ];
[ViewController release];
[db_detail release];
}

Resources