I am using an NSThread and setting the stack size for it as follows:
thread=[[NSThread alloc]initWithTarget:self selector:#selector(fibnocciForLoop) object:nil];
[thread setStackSize:12];
[thread start];
As written Apple docs for for -[NSThread setStackSize:]:
Discussion
You must call this method before starting your thread. Setting the stack size after the thread has started changes the attribute size (which is reflected by the stackSize method), but it does not affect the actual number of pages set aside for the thread.
But when I check the stack size later in the debugger I don't get the value I set:
print (int)[thread stackSize]
$1 = 524288
My question is why does the setStackSize: method exist if it does nothing?
Please let me know where I am wrong, or whether the API for setStackSize: is not of any use?
EDIT:
Refer to Answer by #Josh Caswell for this question, i missed the K in 4K , and hence the above code will work fine as under:
thread=[[NSThread alloc]initWithTarget:self
selector:#selector(fibnocciForLoop) object:nil];
[thread setStackSize:12*4096];//4K=4096
[thread start];
EXTENSION OF THIS QUESTION:
Can someone kindly explain as to why Apple gave this method setStackSize, and how and when to use this particular method, because it requires a lot of calculations for the user to calculate as to how many bytes are/will be used.
I want to know its exact purpose in NSThread?
Thanks!
The setStackSize: documentation also says:
The stack size for the receiver. This value must be in bytes and a multiple of 4KB.
12 is not a multiple of 4K, so your NSThread ignores your setting and probably uses its default, which appears to be 128 pages (a page on iOS (and OS X) being 4KB), or 4 MB.
It's not clear what you want 12 to mean, but you'll need to change it to indicate at least 4096 bytes if you want NSThread to use your setting.
Just by reading the documentation you linked, have you tried calling [setStackSize:12] after [start]?
thread=[[NSThread alloc]initWithTarget:self selector:#selector(fibnocciForLoop) object:nil];
[thread start];
[thread setStackSize:4096]; // multiple of 4KB
Edit: Ok, nevermind. I totally read the documentation wrong. Do not do this.
Related
Occasionally I have to do a popup alert window in my Cocoa code segments. Previously I used NSAlert directly then have runModal to go while I found that the NSRunAlertPanel is more easier to achieve my goal. So I decided to switch all my alert functions to NSRunAlertPanel. It seemed okay at most time。
Now I'm adding multithreading. I found that NSRunAlertPanel appears clearly slower than NSAlert when calling back in the main thread.
Code segments:
Firstly I create a thread:
[NSThread detachNewThreadSelector: #selector(tryRunLoop:) toTarget:self withObject:nil];
Then this functiontryRunLoop in this thread call the alert window function in the main thread:
while(1)
[self performSelectorOnMainThread:#selector(showAlert:) withObject:anObject waitUntilDone:YES];
The function showAlert in main thread do the rest things:
NSRunAlertPanel(#"Warning:",#"Just testing", #"YES", nil, nil);
As time goes by the response of the popup window appears slower and slower.If I use NSAlert instead of NSRunAlertPanel, or did not run the popup method in main thread, the symptom should disappear.
I also found that the CPU usage was also different between these two methods. Obviously NSAlert costs low CPU usage while hitting the button all the time.
Is someone able to explain these phenomenons?
PS: I was not allowed to put the whole original project online so that I've created a simple Cocoa project in Github to simulate the symptom and the URL ,please take a look at the Known issues in Readme file at first.
Alright, the short answer is don't use NSRunAlertPanel. That family of functions have been discouraged for some time now, and superseded by NSAlert. Use NSAlert instead.
(Unfortunately the class reference for NSRunAlertPanel etc. doesn't mention this; I'm trying to remember where it was first documented; perhaps a release note)
For an iCloud plugin I'm writing, I subscribe my iCloud manager class to these iCloud NSMetaDataQuery observers:
// Add a predicate for finding the documents
NSString* filePattern = [NSString stringWithFormat:#"*.%#", #"*"];
self.metadataQuery = [[NSMetadataQuery alloc] init];
// Before starting to query, it is required to set the search scope.
arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
// It is also required to set a search predicate.
[self.metadataQuery setPredicate:[NSPredicate predicateWithFormat:#"%K LIKE %#", NSMetadataItemFSNameKey, filePattern]];
// Listen for the second phase live-updating
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(queryDidReceiveNotification:) name:NSMetadataQueryDidUpdateNotification object:nil];
// Listen for the first phase gathering
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(queryIsDoneGathering:) name:NSMetadataQueryDidFinishGatheringNotification
object:nil];
[self.metadataQuery startQuery];
The problem is that none of these selectors are actually ever called back, not even once, and I especially need the NSMetaDataQueryDidUpdateNotification to track upload/download progress of files in the cloud.
An odd thing is that I had this working the other day, but somehow it just stopped working and I've starred myself blind in trying to figure out what the problem actually is. By subscriping to the NSMetadataQueryDidStartGatheringNotification I can see that it does start, but it's like it never finishes. It is quite weird.
I was wondering if anyone have any clue at all as what to be wrong with the above code? Or where else I can look for the problem.
Thank you for your time :)
Make sure you start the NSMetadataQuery in the main thread. Back then this requirement was not documented.
This was quite the secret to dig up. I don't know if you've given up by now, but at long last, I might be able to help.
It turns out that for some (all?) C++ app configurations, there is a message pump that doesn't run automatically. In my app, I finally started getting my expected callbacks after placing a loop like this following my [m_query startQuery] call:
// make it look syncronous for now
while( m_state != finished )
{
Check_For_Interruption();
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:timeslice]]; //<--**this line is the key**
}
where the callbacks are setup to correctly update the m_state variable.
My example just blocks, using it's own thread timeslice to run the loop (unless interrupted by a timeout being reached), but this could also be set up in an asynchronous way.
Another thing to note for those who go overboard on legacy support:
This method did cause the app to start leaking mach ports on OS X 10.9 and older. Haven't seen any problems on anything newer than that, though.
I'm working on a kiosk style slideshow app. I have a UIScrollView which shows the slides, and a factory class, which generates the slides. The "slides" themselves are UIViewController subclasses, which are loaded out from XIB files and customized by the factory class. In my main view controller, I set up the scroll view and start a timer. The timer calls a "reload" method every N seconds, which handles the reload and call to the factory class.
The method that the factory class uses looks something like this:
- (SlideViewController *)slideFromManagedObject:(Slide *)managedObject{
NSInteger slideType = [managedObject slideType];
switch(slideType){
case kSlideTypeA:
{
//
// configure arguments here
//
return [[SlideViewController alloc] initWithArgument:argument] autorelease];
break;
}
//
// More types here...
//
default:
break;
}
}
I haven't yet gotten to the point of defining all of my cases, but the ones that are filled out seem to cause jumps in memory usage. If I add return [[[UIViewController alloc] init] autorelease]; right before the switch/case, I get no visible view, as expected, but I also don't see those memory increases. I'm not sure, but I suspect that it's the "C blocks" that I'm wrapping my slide generation code in.
Some things to note:
When the app starts, I see the memory plateau from about 400 kilobytes to around double that. Then, when the slides progress, any of the slides whose generation code is contained in curly braces is called, the memory plateaus upwards again.
This behavior only seems to happen once per launch - when the app loops through all of the slides, the plateaus to_not_ happen again. However if the app is backgrounded and then relaunched, the plateaus do occur again, consuming even more memory.
When I left the app to run overnight, for about 10 hours and forty minutes, the memory usage had slowly climbed from about 1.44 megabytes to somewhere closer to 1.57 megabytes. I suspect that there are/were some other leaks in there that may have been fixed by my tweaking, but the main jump from about 800 kilobytes to somewhere between 1.4 and 1.5 megabytes is still an issue.
Instruments does not report any leaks, but the plateauing concerns me.
What could be causing the increased memory?
EDIT:
So I don't think it's the blocks, since using an if/else seems to do the same thing.
Here's a screenshot of the Allocations instrument running:
Where could possibly be holding on to these views?
One possible explanation for what you are seeing is some caching that UIKit (I assume) is doing of your objects (don't know what they are, but I think of images mostly).
Caching is often used during transitions and for other internalities of UIKit.
UIKit empties its caches usually when a memory warning is received, so you could try and send one to see what happens. In actuality, I suspect that results of sending a memory warning will not be very easy to analyze, since all of your views are also unloaded, hence memory will go down forcibly. But you can try...
As to how sending a memory warning to the device (as opposed to the simulator), here you find an useful S.O. post.
I feel that i don't fully understand difference between KVO and NSNotification... They seem to be so similar...
Could you make some example showing when is best to use one method and when the other ?
I don't speak about Bind and IB, but i mean add Observer programmatically in my code with NSNotificationCenter or KVO
[self.preferenceController addObserver:self
forKeyPath:#"color"
options:NSKeyValueObservingOptionOld
context:#"Color-change"
];
KVO only works on values, NSNotification can be used for value changes but it can be used for anything and can carry a much greater payload.
For example, you could have an NSNotification posted whenever a file has finished downloading and the userInfo could contain the length of time it took, the number of bytes downloaded and the filesystem path that the file has been saved to.
I'm beta testing my new Mac App which works great on my two MacBook Pro's, and on one other beta tester's iMac. But with two other of my beta testers (both having the exact same osx as I do, 10.6.7) my app window won't open at launch.
Upon inspecting their console logs, I narrowed the problem down to the showWindow call on my class MainWindowController, a subclass of NSWindowController.
m_pMainWindowController= [[MainWindowController alloc] initWithWindowNibName:MAIN_WINDOW_NIB_NAME];
[m_pMainWindowController showWindow:nil];
The showWindow call triggers all the viewController's awakeFromNib methods to be called and this all seems to happen correctly, but right before showWindow is to return, this message is sent to the console from my app:
-[__NSPlaceholderDictionary initWithObjects:forKeys:]: number of objects (0) not equal to number of keys (2)
-[__NSPlaceholderDictionary initWithObjects:forKeys:]: number of objects (0) not equal to number of keys (2)
I am finding this bug very hard to fix because I can't reproduce it on my Macs, and it doesn't appear to be originating in any of my code.
Any insight would be greatly appreciated.
I figured it out. The problem was in a drawRect function. I was initializing a NSDictionary for font attributes, and did not check to see if a certain font was available to be loaded. Thus loading a nil into an NSDictionary. Classic noob mistake.