100% memory leak in gcd block - xcode

I have an arc-enabled project which has PersonModel class:
// .h
#interface PersonModel : NSObject
#property (strong, nonatomic) NSString *photoUrl;
#property (strong, nonatomic) UIImage *photo;
#property (strong, nonatomic) NSString *fio;
#end
// .m
#implementation PersonModel
#synthesize photoUrl;
#synthesize photo = _photo;
#synthesize fio;
- (UIImage *)photo
{
if (_photo == nil && self.photoUrl) {
_photo = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:self.photoUrl]]];
}
return _photo;
}
#end
photo getter is invoked using gcd:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
UIImage *cellImage = model.photo;
});
On line
_photo = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:self.photoUrl]]];
Instruments shows 100% memory leak. As far as I know arc does not work on threads except main thread. So is there any way of fixing this issue?

Related

During my SKProductRequest my UIButtons and UILabels become nil. (XCODE 7)

First time using XCODE and Objective C. Having an issue with my UIButtons and UILabels becoming nil during my SKProductRequest method.
Below is my ShopViewController.m, where initially call my 3 UIButtons and my UILabel. In the viewDidLoad my UIButtons and Label have content.
My Shop page loads correctly but once the ProductsRequest method is called the UIButtons and UILabels become nil, not sure why. All the items are (strong, nonatomic) properties in the .h file and have been linked to the referencing Outlets in the ShopViewController. Any help is really appreciated.
ShopViewController.m below the product request is made with the GetProductInfo method. Which is called from my *homeViewController when I press the buy button on the main game viewController.
#import "ShopViewController.h"
#import "ViewController.h"
#interface ShopViewController ()
#property (strong, nonatomic) ViewController *homeViewController;
#end
#implementation ShopViewController
#synthesize fvProductTitle;
- (void)viewDidLoad {
[super viewDidLoad];
_fvBuyButton.enabled = YES;
_ddBuyButton.enabled = NO;
_bundleBuyButton.enabled = NO;
fvProductTitle.text = #"don't read this";
}
- (IBAction)buyFVProduct:(id)sender {
SKPayment *payment = [SKPayment paymentWithProduct:_fvProduct];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (IBAction)buyDDProduct:(id)sender {
SKPayment *payment = [SKPayment paymentWithProduct:_ddProduct];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (IBAction)buyBundleProduct:(id)sender {
SKPayment *payment = [SKPayment paymentWithProduct:_bundleProduct];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void) getProductInfo:(ViewController *) viewController {
_homeViewController = viewController;
if ([SKPaymentQueue canMakePayments])
{
SKProductsRequest *request = [[SKProductsRequest alloc]
initWithProductIdentifiers:
[NSSet setWithObjects:self.bundleProductID, self.ddProductID, self.fvProductID, nil]];
request.delegate = self;
[request start];
}
else{
_fvProductDescription.text = #"please enable app purchases";
}
}
#pragma mark -
#pragma mark SKProductsRequestDelegate
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSArray *products = response.products;
if (products.count != 0)
{
_fvProduct = products[2];
_fvBuyButton.enabled = YES;
fvProductTitle.text = _fvProduct.localizedTitle;
_ddProduct = products[1];
_ddBuyButton.enabled = YES;
_ddProductTitle.text = _ddProduct.localizedTitle;
_bundleProduct = products[0];
_bundleBuyButton.enabled = YES;
_bundleProductTitle.text = _bundleProduct.localizedTitle;
} else {
fvProductTitle.text = #"Full Version Product not found";
_ddProductTitle.text = #"Dirty Dozen Product not found";
_bundleProductTitle.text = #"Bundle Product not found";
}
products = response.invalidProductIdentifiers;
}
#pragma mark -
#pragma mark SKPaymentTransactionObserver
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
[self unlockFullVersion];
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(#"Transaction Failed");
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
break;
default:
break;
}
}
}
Here is my ShopViewController.h to see properties I have set up.
#import <UIKit/UIKit.h>
#import <StoreKit/StoreKit.h>
#interface ShopViewController : UIViewController <SKPaymentTransactionObserver, SKProductsRequestDelegate> {
}
#property (nonatomic) BOOL *isFullVersionAvailable;
// Store Kit
#property (strong, nonatomic) SKProduct *fvProduct;
#property (strong, nonatomic) SKProduct *ddProduct;
#property (strong, nonatomic) SKProduct *bundleProduct;
#property (strong, nonatomic) NSString *fvProductID;
#property (strong, nonatomic) NSString *ddProductID;
#property (strong, nonatomic) NSString *bundleProductID;
#property (strong, nonatomic) IBOutlet UIButton *fvBuyButton;
#property (strong, nonatomic) IBOutlet UIButton *ddBuyButton;
#property (strong, nonatomic) IBOutlet UIButton *bundleBuyButton;
#property (strong, nonatomic) IBOutlet UILabel *fvProductTitle;
#property (strong, nonatomic) IBOutlet UILabel *ddProductTitle;
#property (strong, nonatomic) IBOutlet UILabel *bundleProductTitle;
#property (strong, nonatomic) IBOutlet UITextView *fvProductDescription;
- (IBAction)buyFVProduct:(id)sender;
- (IBAction)buyDDProduct:(id)sender;
- (IBAction)buyBundleProduct:(id)sender;
- (void)getProductInfo:(UIViewController *)viewController;
#end
My ViewController.m below, my purchaseItem is what the user presses to transition to the shop page and calls the getProductInfo method.
- (IBAction)purchaseItem:(id)sender {
shopViewController.fvProductID = #"BurnsyBadges.FullVersion";
shopViewController.ddProductID = #"BurnsyBadges.DirtyDozen";
shopViewController.bundleProductID = #"BurnsyBadges.Bundle";
[shopViewController getProductInfo: self];
}
To Answer my own question. I had figured it out a few weeks ago and didn't get to update this. But it was a few things I had to correct in order to get multiple ViewControllers to access the Product Purchase Page correctly.
To get the one page working I needed to add a NavigationController to all my ViewControllers.

Compilation fails due to prototype cell

I have a TableViewController subclass with one prototype cell designed in storyboard. Then I am passing the references to the class header etc and for some reason it fails to compile it. But the connections seem fine. I provide you the code and pictures of the build errors and the storyboard. I am using Xcode 4.3.3. Any help is really appreciated.
favTable.h
#import <UIKit/UIKit.h>
#interface favTable : UITableViewController <NSFetchedResultsControllerDelegate>
{
NSFetchedResultsController *fetchedResultsController;
NSManagedObjectContext *managedObjectContext;
NSArray *favArr;
NSMutableArray *favName;
NSMutableArray *favScore;
}
#property (nonatomic, retain) NSArray *favArr;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, strong) NSMutableArray *favName;
#property (nonatomic, strong) NSMutableArray *favScore;
#property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
#property (strong, nonatomic) IBOutlet UITableViewCell *celldes;
#property (strong, nonatomic) IBOutlet UIImageView *cellimage;
#property (strong, nonatomic) IBOutlet UILabel *cellname;
#property (strong, nonatomic) IBOutlet UILabel *cellmanu;
#property (strong, nonatomic) IBOutlet UILabel *cellscore;
#end
favTable.m
#import "favTable.h"
#import "ecoAppDelegate.h"
#interface favTable ()
#end
#implementation favTable
#synthesize favArr;
#synthesize managedObjectContext;
#synthesize fetchedResultsController;
#synthesize favName;
#synthesize favScore;
#synthesize celldes;
#synthesize cellimage;
#synthesize cellname;
#synthesize cellmanu;
#synthesize cellscore;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Favorites";
self.navigationController.navigationBar.translucent = NO;
// passing the array of addedtofavorites to the total one with all favorites
self.managedObjectContext = ((ecoAppDelegate *) [UIApplication sharedApplication].delegate).managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"FavoritesInfo" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
fetchRequest.resultType = NSDictionaryResultType;
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:#"name", nil]];
NSError *error=nil;
self.favArr=[[self.managedObjectContext executeFetchRequest:fetchRequest error:&error]mutableCopy];
if (error!=nil) {
NSLog(#" fetchError=%#,details=%#",error,error.userInfo);
}
self.favName = [[self.favArr valueForKey:#"name"] mutableCopy];
self.favScore = [[self.favArr valueForKey:#"score"] mutableCopy];
}
- (void)viewDidUnload
{
[self setCelldes:nil];
[self setCellimage:nil];
[self setCellname:nil];
[self setCellmanu:nil];
[self setCellscore:nil];
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#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.
return [favName count];;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
// Configure the cell...
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cellname.text = #"Test";
return cell;
}
#end
I moved manually the IB outlets into a separate custom cell class and then linked the references to the storyboard (maybe this is fixed in newer versions)
Then applied that cell style in the prototype cell and simply changed the content of the UI items of my cell using the identifier (no tag was needed)

Adding objects to array NSXMlParser no data

I'm trying to make a XML-parser that saves data from YR.no-API. The parser should add data to these two datastructures. My problem is when i try to add a WeatherTimeData object to my array in WeatherData, it seems like the objects doesnt get added, the following count always give me zero
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementname namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementname isEqualToString:#"time"])
{
[self.weatherdata.timedata addObject:currentWeatherTimeData];
NSLog(#"amount of objects in timedata-array %d", [[self.weatherdata timedata] count]);
}
These are my two data-structures, i alloc weatherData in the following method
-(id) loadXMLByURL:(NSString *)urlString
{
_weatherdata = [[WeatherData alloc] init];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
parser = [[NSXMLParser alloc] initWithData:data];
parser.delegate = self;
[parser parse];
return self;
}
Do i have to alloc the array inside of the weatherdata object?
WeatherData.h
#interface WeatherData : NSObject
#property (strong, nonatomic)NSString *town;
#property (strong, nonatomic)NSString *country;
#property (strong, nonatomic)NSMutableArray *timedata;
#end
WeatherData.m
#implementation WeatherData
#synthesize town = _town;
#synthesize country = _country;
#synthesize timedata = _timedata;
#end
WeatherTimeData.h
#interface WeatherTimeData : NSObject
#property (strong, nonatomic)NSDate *startTime;
#property (strong, nonatomic)NSDate *endTime;
#property (strong, nonatomic)NSString *iconSymbol;
#property (strong, nonatomic)NSString *windDirection;
#property (strong, nonatomic)NSString *windSpeed;
#property (strong, nonatomic)NSString *temprature;
#property (strong, nonatomic)NSString *preassure;
#end
WeatherTimeData.m
#implementation WeatherTimeData
#synthesize startTime = _startTime;
#synthesize endTime = _endTime;
#synthesize iconSymbol = _iconSymbol;
#synthesize windDirection = _windDirection;
#synthesize windSpeed = _windSPeed;
#synthesize temprature = _temprature;
#synthesize preassure = _preassure;
#end
This type of problem is classically because the object hasn't been allocated, and given Objective-C allows messages to be sent to nil the programmer doesn't notice.
I think it would be nice to be able to provide a runtime environment variable where such events are logged to stdout...
I would suspect that [WeatherTimeData init] isn't creating timedata and that's because you haven't provided an implementation for it; just using #sythensize isn't enough to create the objects.

Range or index out of bounds (App is crashing)

I have an app with ads banner (inner-active) in every view controller (4 views) and i keep getting this error after 2-3-4 minutes that my app is running:
'NSRangeException', reason: '*** -[__NSCFString substringToIndex:]: Range or index out of bounds'
My app is crashing & i can't find the solution for that, but i know for sure that is something with my AD banner issue cau's when i comment the ad banner code everything works great. i can assume that it happens when new request is loading on the banner.
This is the code i'm using for the AD banner:
.h file:
#property (nonatomic, retain) UIView *adBanner;
.m file:
Did synthesize & import for what i need and after that:
- (void)viewWillAppear:(BOOL)animated
{
CGRect frame = CGRectMake(0, 430, 320, 50);
self.adBanner = [[UIView alloc] initWithFrame:frame];
[self.view addSubview:self.adBanner];
// Display ad
if (![InneractiveAd DisplayAd:#"iOS_Test" withType:IaAdType_Banner withRoot:adBanner withReload:60 withParams:optionalParams])
{
adBanner.hidden = YES;
}
}
This is my AppDelegate (don't know why but maybe it something with that too?):
.h file:
#import <UIKit/UIKit.h>
#class RootViewController;
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (nonatomic, strong) RootViewController *rootViewController;
#end
.m file:
#import "AppDelegate.h"
#import "RootViewController.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize rootViewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.rootViewController = [[RootViewController alloc] initWithNibName:nil bundle:NULL];
[self.window addSubview:self.rootViewController.view];
[self.window makeKeyAndVisible];
return YES;
}
I realy don't understand what it could be and how it related to NSCFString :\
Thanks.
Not sure if you got an answer to this but I was getting it with this line of code when there was no internet connection.
NSString *value = [serverOutput substringWithRange:NSMakeRange(2, [serverOutput length] - 2 * 2)];
I had to protect it with a check to the internet connection and an if then statement

splash screen won't show

EDIT 1: changed the code to:
delegate.h:
#import <UIKit/UIKit.h>
#class ViewController;
#interface AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
ViewController *viewController;
UIImageView *splashView;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet ViewController *viewController;
#property (nonatomic, retain) IBOutlet UIImageView *splashView;
- (void)removeSplash;
#end
delegate.m:
#import "AppDelegate.h"
#import "ViewController.h"
#implementation AppDelegate
#synthesize window;
#synthesize viewController;
#synthesize splashView;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
splashView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
splashView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Splash" ofType:#"png"]];
[window addSubview:splashView];
[window bringSubviewToFront:splashView];
[window makeKeyAndVisible];
[self performSelector:#selector(removeSplash) withObject:nil afterDelay:5.0];
[window addSubview:viewController.view];
return YES;
}
- (void)removeSplash {
[splashView removeFromSuperview];
[splashView release];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
EDIT 2:
when I use:
splashView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
splashView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"Splash" ofType:#"png"]];
if (splashView.image == nil) {
NSLog(#"splashView is nil");
}
it logs "splashView is nil"
My Viewcontroller is empty, just for debugging purposes.
As you probably already know, splash screens are discouraged. Since your image is Default.png, isn't it already being shown on app launch automatically?
In any case, the sleep() call is probably blocking the UI. Remove the sleep() and move the statements after it (the removeFromSuperview, etc) to another method in the app delegate. Call this method using performSelector:withObject:afterDelay:. Put the performSelector call where you currently have the sleep call.
Also, you should use the didFinishLaunchingWithOptions method instead of the old applicationDidFinishLaunching method.

Resources