Here I am parsing my JSON Data in a GCD Queue . Here i am using a class method to get the values. In my GCD queue i am allocating and releasing some arrays . Is this a right way to do in a GCD queue or i have to use the __block specifier. Want to clear my confusion
+ (void)startProcessingFeeds:(NSData *)fetchedData{
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^(void) {
NSMutableArray *idArrayTemp = [[NSMutableArray alloc] init];
NSMutableArray *titleArrayTemp = [[NSMutableArray alloc] init];
NSMutableArray *filesArray = [[NSMutableArray alloc] init];
MBFeeds *feeds = [MBFeeds getFeeds];
NSString *response = [[[NSString alloc] initWithData:fetchedData encoding:NSASCIIStringEncoding] autorelease] ;
NSMutableDictionary *newsDic = [response JSONValue];
NSMutableDictionary *tempNested = [newsDic valueForKey:#"data"];
/* here i am taking the values from dictionary and storing that to a array in my Singleton class */
[idArrayTemp release];
[titleArrayTemp release];
[filesArray release];
});
}
If I understand you correctly you are reading data and then storing it in a singleton so you can access it somewhere else. As long as the singleton is ensuring the data is retained (by using retained properties for example) then there should be no problem with your code.
__block is only needed when you want to create a variable out side of a block and have it manipulated inside a block. An example is when using a block to process array data.
Related
I have a memory growth issue in my app.
Since
describing the full code here is intimidating,
I narrowed it down to this simple scenario where I switch back and forth between two view controllers to learn basic memory dynamics.
- (void)viewDidLoad {
[super viewDidLoad];
for (int i=0; i<100000; i++)
{
__weak NSString* str = [NSString stringWithFormat:#"abcsdf"];
str = nil;
}
}
This supposed to show no memory growth, because I allocate 'str' and deallocate 'str' by making 'str' becomes nil, thus losing the owner.
But, the memory keeps growing.
Everytime I load this view controller, the memory keeps growing and never coming back.
Can anyone tell me why is that?
I am using ARC.
Your code snippet includes several interesting things about iOS/OS X memory management.
__weak NSString* str = [NSString stringWithFormat:#"abcsdf"];
str = nil;
The code is the same as the following without ARC.
NSString* str = [[[NSString alloc] initWithFormat:#"abcsdf"] autorelease];
str = nil;
Because stringWithFormat: class method does not begin with "alloc", "new", "copy", or "mutableCopy". It's the naming rule. So the NSString object is retained by an Autorelease Pool. The Autorelease Pool might be in the main Runloop. Thus the NSString object was not deallocated immediately. It causes memory growth. #autoreleasepool solves it.
#autoreleasepool {
__weak NSString* str = [NSString stringWithFormat:#"abcsdf"];
str = nil;
}
The NSString object is deallocated at the end of #autoreleasepool code block.
By the way, [NSString stringWithFormat:#"abcsdf"] might not allocate any memory every time. The reason is that it's static string. Let's use this class for further explanation.
#import <Foundation/Foundation.h>
#interface Test : NSObject
+ (instancetype)test;
#end
#implementation Test
- (void)dealloc {
NSLog(#"Test dealloc");
}
+ (instancetype)test
{
return [[Test alloc] init];
}
#end
Here is test code for __weak.
#autoreleasepool {
NSLog(#"BEGIN: a = [Test test]\n");
__weak Test *a = [Test test];
NSLog(#"END: a = [Test test]\n");
a = nil;
NSLog(#"DONE: a = nil\n");
}
The result of the code.
BEGIN: a = [Test test]
END: a = [Test test]
DONE: a = nil
Test dealloc
You said deallocate 'str' by making 'str' becomes nil, thus losing the owner. It is not correct. a weak variable doesn't have ownership of the object. The Autorelease Pool does have the ownership of the object. That's why the object was deallocated at the end of the #autoreleasepool code block. Take a look at the other test code for this case.
NSLog(#"BEGIN: a = [[Test alloc] init]\n");
__weak Test *a = [[Test alloc] init];
NSLog(#"END: a = [[Test alloc] init]\n");
a = nil;
NSLog(#"DONE: a = nil\n");
You can see a compilation warning from the code.
warning: assigning retained object to weak variable; object will be
released after assignment [-Warc-unsafe-retained-assign]
__weak Test *a = [[Test alloc] init];
^ ~~~~~~~~~~~~~~~~~~~
[[Test alloc] init] doesn't register the object to Autorelease Pool. Well, no need #autoreleasepool any more. And a is __weak variable, so the object will not be retained from anything. Thus the result is
BEGIN: a = [[Test alloc] init]
Test dealloc
END: a = [[Test alloc] init]
DONE: a = nil
No ownership no life. The object was deallocated immediately after it was allocated. I think you wanted to write the code without __weak as the following.
NSLog(#"BEGIN: a = [[Test alloc] init]\n");
Test *a = [[Test alloc] init];
NSLog(#"END: a = [[Test alloc] init]\n");
a = nil;
NSLog(#"DONE: a = nil\n");
The result is as expected. The object was released by assigning nil to the strong variable a. Then no one has the ownership of the object, the object was deallocated.
BEGIN: a = [[Test alloc] init]
END: a = [[Test alloc] init]
Test dealloc
DONE: a = nil
In my application i have enabled the ARC. But in my application following lines gives me memory leaks according to instruments. It is in ios 7.0.
-(id)init{
variables = [[NSMutableArray alloc] init]; // Leak
events = [[NSMutableArray alloc] init]; //Leak
return self;
}
Update
But in my app if i do something like below it does not show me any leak. But i can't add items in to the variables.
-(id)init{
variables = [[[NSMutableArray alloc] init] copy]; // No Leak
events = [[[NSMutableArray alloc] init] copy]; //No Leak
return self;
}
--
NSString *utfString =[NSString stringWithUTF8String:(const char *)attr->children->content];//Leak
--
-(NSObject*)createObjectForClass:(NSString*)className{
Class cls = NSClassFromString(className);
NSObject *object = [[cls alloc]init]; //Leak
if(cls != nil){
CFRelease((__bridge CFTypeRef)(cls));
}
return object;
}
Does anyone has any idea how to fix this?
My guess right now is that your entire object is leaking, which means that the NSMutableArrays created in -init also leak. The version that calls copy isn't leaking because the copy is probably returning a singleton instance of NSArray (as there are zero elements in it, and it's an immutable NSArray, there's probably a singleton instance for that).
i am constructing All data to look like a response data dictionary from a server.
Now, newsFeedsDict1 which should Dictionary for both Bolly and Global is not only showing all data inside Global dictionary only. While my for loop is running its showing correct data for Bolly. but for 2nd time its showing Bolly's data also in Global dictionary.
if(internetStatus == NotReachable)
{
NSMutableArray *titleArr = [[NSMutableArray alloc] init];
NSMutableArray *wholeFeeds = [[[NSMutableArray alloc] init] autorelease];
[titleArr addObject:#"Bolly"];
[titleArr addObject:#"Global"];
for (NSString *title in titleArr) {
//titleArr = [[NSUserDefaults standardUserDefaults] objectForKey:#"TitleArray"];
NSLog(#"TITle arr %#",titleArr);
NSLog(#"No internet");
OrderedDictionary *newsFeedsDict1 = [[[OrderedDictionary alloc] init] autorelease];
NSMutableDictionary *newsFeedsDict = [[[NSMutableDictionary alloc] init] autorelease];
NSMutableArray *myLocalArray= [[[NSMutableArray alloc] init] autorelease];
myLocalArray = [[Database sharedDatabase] getArticleData:title];
NSMutableDictionary *articleDict = [[[NSMutableDictionary alloc] init] autorelease];
[articleDict setObject:myLocalArray forKey:#"article"];
[newsFeedsDict setObject:articleDict forKey:#"Articles"];
[newsFeedsDict setObject:title forKey:#"#name"];
[newsFeedsDict1 setObject:newsFeedsDict forKey:title];
[wholeFeeds addObject:newsFeedsDict1];
NSLog(#"news feed dict %#",newsFeedsDict1);
NSMutableDictionary *temparticleDictionary = [[NSMutableDictionary alloc] init];
self.articleDictionary = temparticleDictionary;
self.categoriesDictionary = [[NSMutableDictionary alloc] init];
self.categoriesDictionary =newsFeedsDict1;
[self createArticleDictionaryForCategory:newsFeedsDict];
}
}
It's difficult to tell what your code is supposed to do, and how you can tell that one dictionary has the same content as another. A couple problems:
NSMutableArray *myLocalArray= [[[NSMutableArray alloc] init] autorelease];
myLocalArray = [[Database sharedDatabase] getArticleData:title];
The first line is entirely unnecessary. You're creating a new array, assigning it to myLocalArray, and then assigning something else to myLocalArray. You do the same later with self.categoriesDictionary. This leads me to believe that you have some misunderstanding with respect to object pointers.
So, the array that you get from your shared database ends up at myLocalArray, and you then add that array to the dictionary at articleDict, and then add articleDict to newsFeedDict and in turn add that to newsFeedDict1. And then you log newsFeedDict1. You do exactly the same for both your titles, #"Bolly" and #"Global", so it's not at all surprising that you see the same output in both cases.
I'm having a hard time seeing why you expect the output to be different, and I have to guess that again it's due to a misunderstanding of what happens when you assign one object pointer to another. Or, perhaps you're expecting the array that you get from [[Database sharedDatabase] getArticleData:title]; to be different because you're passing in different titles. Maybe you really should be getting different arrays there; it would be a good idea to look at what happens in that -getArticleData: method and whether it really is giving you the right results for each title.
If that doesn't help, take some time to clean up your code so that it's easier for us, and more importantly, for you to really see what's going on. Also, please edit your question to give a better description of what you're seeing and how that's different from what you expect to see.
Can you write the snippet for *getArticleData()* method
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSError *error = nil;
NSURL *urlRequest = [NSURL URLWithString:[NSString stringWithFormat:#"...", URL]];
NSString *json = [NSString stringWithContentsOfURL:urlRequest
encoding:NSASCIIStringEncoding
error:&error];
JKParseOptionFlags options = JKParseOptionStrict;
NSDictionary *results = [json objectFromJSONStringWithParseOptions:options];
NSString *body = [[results objectForKey:#"item"] objectForKey:#"description"];
Article *article = [[Article alloc] initWithTitle:title URL:URL body:body];
[self.articles insertObject:article atIndex:0];
});
Right outside of that I have [self.tableView reloadData]; but if I call NSLog(#"%d", self.articles.count); right after that it returns 0. Why is it not adding it? If I call an NSLog inside that block accessing article's body property it will print it, so the object seemingly gets created fine. And yes, the method that this is in does get called (by viewDidLoad).
The body gets executed asynchronously, so it doesn't start running that body until some time after your function is done. So all you do is put some code on a queue (which will not be run until later), and check if the article got added to the list (which it won't, until later).
If you check inside the code, that is actually checking a while later, when the queue is done running the code...
I can't tell you more without seeing the declaration of your articles object but what this usually means is that the NSMutableArray object you're trying to use is nil. At the same time that you're logging the article's body property, try logging the articles object as well. If you declared your array as
NSMutableArray *articles;
Then it won't work - articles is still nil and can't accept objects. Declare/instantiate using one of the following options:
NSMutableArray *articles = [NSMutableArray array];
or
NSMutableArray *articles = [[NSMutableArray alloc] init];
I am from android background and I just started working on iPhone
I want to perform this operation in iPhone as I do in Android.
ArrayList<String> aa = new ArrayList<String>();
public void fillArray(String s)
{
aa.add(s);
}
As Binyamin Sharet suggest you have to use NSMutableArray. This class allows you to create a dynamic array. You can perform addition or deletion. On the contrary NSArray is a immutable version of it. You cannot add or delete objects to a NSArray once created.
The same distinction can be applied to NSDictionary and NSMutableDictionary (and other).
Here a simple example.
NSMutableArray* arr = [[NSMutableArray alloc] init];
[arr addObject:#"first string"];
[arr addObject:#"second string"];
An important aspect of NSMutableArray (the same could be applied to other class) is the memory management one. When you add an object to a NSMutableArray it retains objects added to it. So, if you NOT use ARC you have to deal with this aspect.
NSMutableArray* arr = [[NSMutableArray alloc] init];
id obj = [[NSObject alloc] init]; // a general object
[arr addObject:obj];
[obj release];
For further info I suggest you to read about NSMutableArray class reference.
Hope it helps.