Object-c memory alloc IOS 7 - ios

I have a problem with memory full with RNDecryptor (+) in a cycle "for" i call this method es:
for (int i=0; i < [datasource fileCount]; i++) {
...
datacrypto = [RNDecryptor decryptData:datacrypto withSettings:kRNCryptorAES256Settings password:passcode error:nil];
....
}
RNDecryptor allocates memory but the calls do not empty and sooner or later there is no more free memory and CRASH ... its possible dealloc +[RNDecriptor...] between calls or otherwise as a solution ??
thank you.

Here's the implementation of the method.
+ (NSData *)decryptData:(NSData *)theCipherText withSettings:(RNCryptorSettings)settings password:(NSString *)aPassword error:(NSError **)anError
{
RNDecryptor *cryptor = [[self alloc] initWithPassword:aPassword
handler:^(RNCryptor *c, NSData *d) {}];
cryptor.settings = settings;
return [self synchronousResultForCryptor:cryptor data:theCipherText error:anError];
}
It's no a singleton or is there any other branch? If not, you better implement your own singleton pattern.

Related

Memory Allocation with ARC - No leaks but slowly heaping memory

I've started writing my first serious attempt at a hybrid, Cordova/Objective-C program for iOS, and I'm currently hitting some stumbling blocks regarding memory allocations. I need to get the user's Album art to display within the web view. I got the art to display successfully, but now there's a ton of memory being allocated.
Using the "Instruments" tool and comparing Generational Snapshots, I've narrowed my guilty culprits down to these methods - which I all wrote from scratch. But I'm confused - since I'm using automatic reference counting, and that I have everything in autorelease pools, that there shouldn't be any wasted memory. Funny thing is, I see no "leaks" being reported - just a heap that gets bigger, with more and more memory allocated.
I've attached some screenshots of the Instruments tool:
Here are direct links to the images since there is so much text:
http://i.imgur.com/rkc5dhA.png
http://i.imgur.com/U2esgBT.png
http://i.imgur.com/fmt3Mv4.png
Here's the contents of the "BukketHelper.M" class that I made (matches the header, no strong properties or any other definitions of any sort):
-(NSString *) convertULLToNSString:(NSNumber* )guid
{
return [NSString stringWithFormat:#"%llu", [guid unsignedLongLongValue]];
}
-(NSNumber *) convertStringToULL:(NSString *) guid
{
//get string to number
//this causes memory to not be released
unsigned long long ullvalue = strtoull([guid UTF8String], NULL, 10);
NSNumber *numberID = [[NSNumber alloc] initWithUnsignedLongLong:ullvalue];
return numberID;
}
Here's the contents of the "MediaQuery.M" class that I made (this matches the header exactly, no strong properties or other definitions):
-(MPMediaItem*) getMediaItemULL:(NSNumber*)guid
{
#autoreleasepool {
//run the query on
MPMediaQuery *query = [[MPMediaQuery alloc] init];
[query addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:guid forProperty:MPMediaItemPropertyPersistentID]];
//get and return the item
NSArray *mediaResults = [query items];
return [mediaResults firstObject];
}
}
-(MPMediaItem*) getMediaItem:(NSString*)guid
{
#autoreleasepool {
BukketHelper* bh = [[BukketHelper alloc] init];
return [self getMediaItemULL:[bh convertStringToULL:guid]];
}
}
-(UIImage*) getMediaAlbumArtAsUIImage:(NSString*)guid withQuality:(NSNumber*)quality withLength:(NSNumber*)length subsituteImageName:(NSString* )filename
{
return [self getMediaAlbumArtFromMediaItemAsUIImage:[self getMediaItem:guid] withQuality:quality withLength:length subsituteImageName:filename];
}
-(NSString*) getMediaAlbumArtAsBase64:(NSString*)guid withQuality:(NSNumber*)quality withLength:(NSNumber*)length subsituteImageName:(NSString* )filename
{
NSString *base64 = nil;
#autoreleasepool {
UIImage* rawImage = [self getMediaAlbumArtAsUIImage:guid withQuality:quality withLength:length subsituteImageName:filename];
NSData *imageData = nil;
if (rawImage != nil)
{
#autoreleasepool {
//this causes memory to not be released
imageData = UIImageJPEGRepresentation(rawImage, [quality floatValue]);
base64 = [imageData base64EncodedStringWithOptions:0];
}
}
}
return base64;
}
-(UIImage*) getMediaAlbumArtFromMediaItemAsUIImage:(MPMediaItem*)item withQuality:(NSNumber*)quality withLength:(NSNumber*)length subsituteImageName:(NSString* )filename
{
UIImage *rawImage = nil;
#autoreleasepool {
bool successfulArt = NO;
if (item != nil)
{
MPMediaItemArtwork *albumArt = [item valueForProperty:MPMediaItemPropertyArtwork];
if (albumArt != nil) {
#autoreleasepool {
//this causes memory to not be released
rawImage = [albumArt imageWithSize:CGSizeMake([length doubleValue], [length doubleValue])];
successfulArt = YES;
}
}
}
if (successfulArt == NO)
{
rawImage = [UIImage imageNamed:filename];
}
}
return rawImage;
}
So yeah - my question is: What am I doing wrong when it comes to memory allocation and leaks? My current tests are exclusively using album art - so "UIImage imageNamed" shouldn't be the issue (from it's caching). In addition, I've read that ARC cannot release CoreGraphics objects, which could also be the problem.
I really could use some help with this! Thank you!
I ran into the same problem. I think there's a bug in the framework which doesn't release the memory. Basically there's a huge spike in allocated memory each time func imageWithSize(size: CGSize) -> UIImage? is called.
If it helps you any, I noticed that if you call this function passing in the artwork.bounds.size (instead of creating a new image size each time) then the memory gets allocated only once and calling imageWithSize again (with the same dimensions) does not reallocate new memory. This appears to only be true if you pass in the size of the original artwork image and don't return a custom size. If you need a custom size, perhaps you can then resize the UIImage on your own and not rely on this buggy method.

NSMutableArray can not release objects after invoke removeAllObjects

I'm a new guy for developing ios app.
#property (copy, nonatomic) NSMutableArray* dataBufferArray;
Following code run in a callback function.which invoked frequently.
[analyzer.dataBufferArray addObject:[NSNumber numberWithInteger:thisFrame]];
[analyzer.dataBufferArray removeAllObjects];
Code run in ARC.
I found the memory always growing! Finally IOS exit my application cause by huge memory consume.
My question is: why removeAllObjects can not release the memory?
How to resolve it?
post more code
static int analyze(SAMPLE *inputBuffer,
unsigned long framesPerBuffer,
AudioSignalAnalyzer *analyzer) {
SAMPLE *pSample = inputBuffer;
for (long i = 0; i SAMPLE_RATE){
NSArray* unitSampleArray = [analyzer.dataBufferArray subarrayWithRange:NSMakeRange(0, SAMPLE_RATE - 1)];
[analyzer.dataBufferArray removeObjectsInRange:NSMakeRange(0, SAMPLE_RATE - 1)];
//use thread to process
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:analyzer
selector:#selector(decodeSound:)
object:unitSampleArray];
[analyzer.queue addOperation: operation];
}
// for protect
if (analyzer.dataBufferArray.count > SAMPLE_RATE * 12){
NSLog(#"sample in data buffer so big, need clear");
[analyzer.dataBufferArray removeAllObjects];
}
return 0;
}
As you can see, analyze function is callback by AudioQueueNewInput.
I used NSMutableArray add object NSNumber, and I always 'removeObjectsInRange:' them. I use instruments to check the memory, it always growing!
You are using ARC based project there is no need to release memory, it will automatically managed. Your problem is somewhere else please post some more code.

GCD and multiple delegates in iOs

I would like to do the following:
In a class (shared instance) I will have a method that takes as parameters a data object (nsstring) and a delegate. This will create a new background thread and dispatch some calculations on that thread. The thing is that the method may be called hundreds of times with different data and possibly different delegates passed in . I would like the results to go to the correct delegate (I will need to keep the delegates in an array right? or can I just pass them to the background thread as they come and when that thread finishes it will send the result only to that delegate?).
One more thing... all this methods will use a very large data structure (an array with 10000 nsstring objects,they only need to read from it). How do I make sure this is not duplicated on each thread? And is only allocated when needed and deallocated when no thread uses it?
Here is the code I decided to use:
if (!self.dictPasswords) {
// read everything from text
NSString* fileContents = [NSString stringWithContentsOfFile:fileRoot
encoding:NSUTF8StringEncoding error:nil];
// separate by new line
self.dictPasswords = [fileContents componentsSeparatedByCharactersInSet:
[NSCharacterSet newlineCharacterSet]];
}
__weak id<PSPasswordDictionaryVerificationDelegate> wdelegate = delegate;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[wdelegate willBeginPasswordVerificationForPassword:password];
for (NSString *posiblePass in self.dictPasswords) {
if ([password isEqualToString:posiblePass]) {
dispatch_async(dispatch_get_main_queue(), ^{
[wdelegate password:password isInDictionary:YES];
});
return;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
[wdelegate password:password isInDictionary:NO];
});
});
However... after this runs I get a permanent 24MB added to the used memory. I would like to detect when no threads are using the self.DIctPasswords array and deallocate it. It will be read from the file again later if somebody calls this method again...
Thanks for the help guys.
Just let the block capture the delegate.
No need to hold it otherwise
Class
#import <Foundation/Foundation.h>
#protocol ProcessorDelegate;
#interface Processor
- (void)process:(id)data forDelegate:(id<ProcessorDelegate>)delegate;
+ (Processor*)sharedInstance;
#end
#protocol ProcessorDelegate
- (void)processor:(Processor*)processor didProcess:(id)data withResult:(id)result;
#end
#implementation Processor
- (void)process:(id)data forDelegate:(id<ProcessorDelegate>)delegate {
__weak id<ProcessorDelegate> wdelegate = delegate; //capture weak to counter potential cycles
__weak id wself = self;
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSLog(#"WORK");
id result = data; //TODO
[wdelegate processor:wself didProcess:data withResult:result];
});
}
+ (Processor*)sharedInstance {
static Processor *p = nil;
if(!p) {
p = [[Processor alloc] init];
}
return p;
}
#end
DEMO
#interface Demo : NSObject <ProcessorDelegate>
- (void)doIt;
#end
#implementation Demo
- (void)doIt {
[Processor sharedInstance] process:#"TEST" forDelegate:self];
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Demo *d1 = [[Demo alloc] init];
Demo *d2 = [[Demo alloc] init];
Demo *d3 = [[Demo alloc] init];
Demo *d4 = [[Demo alloc] init];
[d1 doIt];
[d2 doIt];
[d3 doIt];
[d4 doIt];
[[NSRunLoop currentRunLoop] run];
}
}
It seems more appropriate to encapsulate the calculations plus data and delegate in a class of its own. Then you can have an array of those objects in your singleton. You may want to consider using NSOperation here.
OMT: Simply pass this large array as a pointer (to each calculation object) and use regular strong properties (not copy) if you're using any properties at all, saving a reference to it using an ivar is fine too. One concern is that this data-structure must be read-only; otherwise (when you'd modify it in each thread), you'd need some data locking.
I have done it with blocks : a singleton that have all the functions you needs (like an API) and a delegate class
// singleton.h
typedef void (^request_handler_t)(NSData* data);
- (void) foo:(NSString *)str withBlock:(request_handler_t)callback;
// singleton.m
- (void) foo:(NSString *)str withBlock:(request_handler_t)callback;{
MyDelegate *delegate = [MyDelegate delegateWithBlock:callback];
[yourMethodThatNeedDelegate:delegate];
}
// MyDelegate.h
+ (MyDelegate*) delegateWithBlock:(api_request_handler_t)block;
- (void)delegateMethod1;
//Delegate.m
+ (MyDelegate*) requestWithBlock:(api_request_handler_t)block;{
//... alloc init
_callback = block;
}
- (void)delegateMethod1;{
// delegate finished the job
block(myResultingData);
}
// Usage :
[MySingleton singleton] foo:(NSString *)str withBlock:^(NSData *data){
//do something with the async data
}];

warning: Attempting to create USE_BLOCK_IN_FRAME

I get this warning in Xcode
warning: Attempting to create USE_BLOCK_IN_FRAME variable with block
that isn't in the frame.
Xcode redirect me to my NSStream
_naturStream = [[NSInputStream alloc] initWithData:natur];
It is random when it does this error, and my application crashes when it is triggered. Anyone tried similar problem ?
thanks
EDIT
in the appDelegate.h
#property (nonatomic, strong) NSInputStream *naturStream;
In the appDelegate.m:
NSData *natur = [NSData dataWithContentsOfURL:[NSURL URLWithString:_locString]];
_naturStream = [[NSInputStream alloc] initWithData:natur];
[_naturStream open];
if (_naturStream) {
NSError *parseError = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithStream:_naturStream options:NSJSONReadingAllowFragments error:&parseError];
if ([jsonObject respondsToSelector:#selector(objectForKey:)]) {
for (NSDictionary *natur in [jsonObject objectForKey:#"results"]) {
_poi = [[POI alloc]init];
[_poi setTitle:[natur objectForKey:#"title"]];
[_poi setLat:[[natur objectForKey:#"lat"]floatValue]];
[_poi setLon:[[natur objectForKey:#"lng"]floatValue]];
[_poi setDistance:[natur objectForKey:#"distance"]];
[_poi setWebUrl:[natur objectForKey:#"webpage"]];
[_naturArray addObject:_poi];
}
}
}
else {
NSLog(#"Failed to open stream.");
}
[_naturStream close];
}
I realized that i forgot [_naturStream close] i don't know if it has solved the problem or not ?
EDIT
Another thing,.... I use a Thread for fetching the JSON data:
dispatch_queue_t jsonParsingQueue = dispatch_queue_create("jsonParsingQueue", NULL);
// execute a task on that queue asynchronously
dispatch_async(jsonParsingQueue, ^{
[self parseJSON];
dispatch_async(dispatch_get_main_queue(), ^{
[_kortvisning updateAnno];
[visListe updateList];
});
});
// release the dispatch queue
dispatch_release(jsonParsingQueue);
Sounds like you're using ARC - if _naturStream is an instance variable for an objective C class, you might need to pull it out and add a __block reference so that ARC knows the scope correctly - but I'm guessing because I don't see how the block is used with the NSInputStream (if you post that part we might know). A good bit is here: http://nachbaur.com/blog/using-gcd-and-blocks-effectively
-- edit --
Ok, now that you posted the rest, I bet it has to do with the _kortvisning and visListe variables. I think you want to pull those out right after you create your queue something like
__block KortVisning *localKortVisning = _kortvisning;
__block NSMutableArray *localVisListe = visListe;
Then access those directly from your final completion handler you're sending back to the main queue.

Runtime error: __NSAutoreleaseNoPool(): ...autoreleased with no pool in place - just leaking

I am getting a list of errors like the following error when I compile my project for iOS.
2011-08-25 12:32:44.016 rtsp[55457:6003]
*** __NSAutoreleaseNoPool(): Object 0x64095a0 of class __NSArrayM
autoreleased with no pool in place - just leaking
It appears because of the following function
- (void) start {
//Existing code
session = [[RTSPClientSession alloc] initWithURL:
[NSURL URLWithString:
#"rtsp://video3.americafree.tv/AFTVComedyH2641000.sdp"]];
[session setup];
NSLog(#"getSDP: --> %#",[ session getSDP ]);
NSArray *array = [session getSubsessions];
for (int i=0; i < [array count]; i++) {
RTSPSubsession *subsession = [array objectAtIndex:i];
[session setupSubsession:subsession clientPortNum:0 ];
subsession.delegate=self;
[subsession increaseReceiveBufferTo:2000000];
NSLog(#"%#", [subsession getProtocolName]);
NSLog(#"%#", [subsession getCodecName]);
NSLog(#"%#", [subsession getMediumName]);
NSLog(#"%d", [subsession getSDP_VideoHeight]);
NSLog(#"%d", [subsession getServerPortNum]);
}
[session play];
NSLog(#"error: --> %#",[session getLastErrorString]);
[session runEventLoop:rawsdp];
}
When I add and NSAutoreleasePool to my function
- (void) start {
NSAutoReleasePool *pool=[[NSAutoReleasePool alloc] init];
session = [[RTSPClientSession alloc] initWithURL:[NSURL ...
...
[pool drain];
}
The error is gone but I don't get any output from my function. Is adding NSAutoreleasePool the right solution?
You get the message on the console because you are running the start method on a background thread and have not placed an Autorelease pool in place that will take care of reclaiming objects once they have been released (release count == 0 ),this doesnt happen in the main thread because the main thread already has a pool in place, for background threads u spawn you are responsible to set up the autorelease pool... your solution is the right solution to the problem.. so here is an example of when to and where to use autorelease pool
One way to spawn something to execute in the background is by calling performSelectorInBackground method of NSObject which i assume you are doing
[myObject performSelectorInBackground:(#selector(myBackgroundMethod:) withObject:nil];
Now this method is going to execute on a background thread and you need to place an Autorelease pool in place in order for it not to leak, like so
-(void)myBackgroundMethod:(id)sender
{
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
//do stuff
[pool release];
}
hope that clears it up
Daniel

Resources