Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development > iPhone SDK Development - Advanced Discussion

Reply
 
LinkBack Thread Tools Display Modes
Old 02-10-2011, 04:14 PM   #1 (permalink)
Registered Member
 
Join Date: Sep 2010
Posts: 26
javadude is on a distinguished road
Default NSNumber leaks using predicates

Hi guys,
I've got an object that takes an expression like "23.67*$MY_KEY" and a dictionary with the values mapping to the keys used in the expression. I pipe the key values into a NSPredicate and cast that to a NSExpression to evaluate the expression.

Code:
#import "ExpressionEval.h"

@implementation ExpressionEval

// Evaluates a math expression by substituting in values from a dictionary into known variables
+ (NSDecimalNumber *) calcExpresssion:(NSString *)expr  variables:(NSDictionary *)values error:(NSError **)err {
	NSDecimalNumber *result;
	NSNumber *tempNum;
	NSMutableDictionary *substituteValues = [NSMutableDictionary dictionary];

	// Cannot process if there is no expression
	if (!expr) {
		NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary];
		[errorDetail setValue:@"Tried to calculate an expression that is nil" forKey:NSLocalizedDescriptionKey];
		*err = [NSError errorWithDomain:@"myDomain" code:100 userInfo:errorDetail];
		
		return nil;
	}
		
	NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
	[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
	
	// Covert string values in dictionary with NSNumber instances
	for (NSString *key in values) {
		id value = [values objectForKey:key];
		
		if ([value isKindOfClass:[NSString class]]) {
			// If not a number nil will be returned, add to variable/value dictionary
			tempNum = [formatter numberFromString:value];
			if (tempNum != nil) {
				[substituteValues setValue:tempNum forKey:key];
			}
		}
	}
	
	[formatter release], formatter = nil;
	
	// Add a dummy right hand side to the equation if non exists
	NSMutableString *expression = [NSMutableString stringWithString:expr];
	NSRange range = [expr rangeOfString:@"=="];
	if (range.location == NSNotFound) {
		[expression appendFormat:@" == 0"];
	}
	
	@try {
		// Substite in variable values in expression
		NSPredicate *predicate = [NSPredicate predicateWithFormat:expression];
		predicate = [predicate predicateWithSubstitutionVariables:substituteValues];
		// Evaluate the left hand side of the expression
		NSExpression *algExpression = [(NSExpression *)predicate leftExpression];
		result = [algExpression expressionValueWithObject:nil context:nil];
	}
	@catch (id exception) {
		NSMutableDictionary *errorDetail = [NSMutableDictionary dictionary];
		[errorDetail setValue:@"Tried to calculate an expression that is nil" forKey:NSLocalizedDescriptionKey];
		*err = [NSError errorWithDomain:@"myDomain" code:100 userInfo:errorDetail];
		
		return nil;
	}
	
	return result;
}

@end
On running this with the Leaks performance tool Im getting the following leaks:

Code:
Leaked Object	#	Address	Size	Responsible Library	Responsible Frame
NSCFNumber	21	< multiple >	336	Foundation	getObjectValue
NSCFNumber	21	< multiple >	336	Foundation	getObjectValue
Im suspecting the NSMutableDictionary loaded with NSNumber instances. I have no idea what could be the problem here as I don't know the mechanics of the NSPredicate and NSExpression behind the scenes. Could anyone shine some light on a solution?
javadude is offline   Reply With Quote
Old 02-10-2011, 06:21 PM   #2 (permalink)
Registered Member
 
Join Date: Sep 2010
Posts: 26
javadude is on a distinguished road
Default

Aha, got it! It was coming from the NSNumberFormatter parsing non-numbers. I assumed it would be safe and merely return a nil but instead was causing leaks. Below is the fixed code snippet:

Code:
// Only convert to number is string is numeric
double holder;
NSScanner *scan = [NSScanner scannerWithString:value];
if ([scan scanDouble:&holder] && [scan isAtEnd]) {
	tempNum = [formatter numberFromString:value];
}
else {
	tempNum = nil;
}
			
// If not a number nil will be returned, add to variable/value dictionary
if (tempNum != nil) {
	[substituteValues setValue:tempNum forKey:key];
}
javadude is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 402
17 members and 385 guests
Brandt, coolman, Domele, fredidf, Free App Monster, givensur, iAppDeveloper, jbro, Kryckter, locombiano89, Mah6447, Meoz, simplymuzik3, SLIC, stevenkik, Tomsky, WeaselPig
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,646
Threads: 94,111
Posts: 402,863
Top Poster: BrianSlick (7,990)
Welcome to our newest member, locombiano89
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 05:51 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0