iPhone headache - Threads, notifications, and URL Async connections - iphone

Some code instead of a long explanation.
The problem is :
When called from viewDidLoad, the server call triggers the delegates methods (connectionDidFinishLoading, etc...). But when called from XMLFileFullParsed, the request is launched to the server, but those same methods are not triggered.
If i call [self loadXMLDatas] instead of threading it, both server calls work fine.
Why ?
I start here :
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(foundaTag:) name:#"foundaTag" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(XMLFileFullParsed:) name:#"XMLFileFullParsed" object:nil];
self.server = [[ServerCommManager alloc] initWithServer:#"http://someserver/"];
[self.server sendQuestionWithCallIdentifier:#"IDENTIFIER" onPage:#"testpage.php" withParams:nil sendAnswerToObject:self]; // -- This one works
[NSThread detachNewThreadSelector:#selector(loadXMLDatas) toTarget:self withObject:nil];
}
- (void) loadXMLDatas {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Do things, create a XMLparser, start to parse.
[pool release];
}
- (void) XMLFileFullParsed:(NSNotification*)notification {
[self.server sendQuestionWithCallIdentifier:#"IDENTIFIER" onPage:#"testpage.php" withParams:nil sendAnswerToObject:self]; // -- This one doesn't work
}
XMLParser.m
- (void) doYourJob {
[self doTheJob];
[[NSNotificationCenter defaultCenter] postNotificationName:#"XMLFileFullParsed" object:nil userInfo:nil];
}
- (void) doTheJob:(XMLTag*)tag {
if ([tag.name isEqualToString:#"searchedtag"]) {
theData = extract some datas
[[NSNotificationCenter defaultCenter] postNotificationName:#"foundaTag" object:self userInfo:[NSDictionary dictionaryWithObject:theData forKey:#"data"]];
return;
}
for (XMLTag* aTag in tag.childtags) {
[self doTheJob:aTag];
}
}
Deep inside the server comm.m
- (void) executeRequest {
some init
self.connection = [NSURLConnection connectionWithRequest:urlRequest delegate:self];
}
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response {
}
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
}
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
{
}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
}

From the code you've given, the notification is being posted from another Thread rather than the Main Thread where you've registered the observer.
In Apple's Notification Documentation, it says
In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself.
What you can do is move the notification into it's own method and then use performSelectorOnMainThread like so:
- (void) doTheJob:(XMLTag*)tag {
if ([tag.name isEqualToString:#"searchedtag"]) {
theData = extract some datas
[self performSelectorOnMainThread:#selector(sendNotification:) withObject:theData waitUntilDone:YES];
return;
}
for (XMLTag* aTag in tag.childtags) {
[self doTheJob:aTag];
}
}
- (void)sendNotification:(NSArray *)theData {
[[NSNotificationCenter defaultCenter] postNotificationName:#"foundaTag" object:self userInfo:[NSDictionary dictionaryWithObject:theData forKey:#"data"]];
}

Related

Getting NSNotification to Work?

I'm currently trying to get NSNotification to work but I'm having some trouble.
I have two (2) ViewControllers: A. MainViewController & B. LoginViewController.
In my MainViewController I have a logout button that will send a url to my LoginViewController to load it (without showing my loginView). However, it's not working.
In my MainViewController this is what I have:
- (IBAction)logout:(id)sender {
NSURL *logoutURL = [NSURL URLWithString:#"https://myurl.com/logout"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"logoutInitiated" object:logoutURL];
}
This is what I have in my LoginViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
WebView.delegate = self;
WebView.scalesPageToFit = YES;
WebView.multipleTouchEnabled = YES;
loadCount = 0;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(submitLogout) name:#"logoutInitiated" object:nil];
}
- (IBAction)submitLogout:(NSNotification*)notification {
[WebView stopLoading];
NSURL * signOutUrl = (NSURL*)[notification object];
[self loadURL:nil withURL:signOutUrl];
}
My problem is that when I press the logoutButton nothing happens. (Using NSLogs, I see that it never triggers the next step) Thank you!!!!
This is because your method name you are passing in selector is wrong. You need to add colon : at submitLogout: suffix
Use
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(submitLogout:) name:#"logoutInitiated" object:nil];
in place of
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(submitLogout) name:#"logoutInitiated" object:nil];
Hope it helps you.
When you add self as an observer, you use the selector "submitLogout" without a semicolon! But your method has an argument, so the correct selector would be #selector(submitLogout:).
Note the SEMICOLON
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(**submitLogout:**) name:#"logoutInitiated" object:nil];
- (IBAction)logout:(id)sender
{
NSURL *logoutURL = [NSURL URLWithString:#"https://myurl.com/logout"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"logoutInitiated" object:nil userInfo:[NSDictionary dictionaryWithObjectsAndKeys:logoutURL,#"RECEIVED_URL", nil]];
}
- (IBAction)submitLogout:(NSNotification*)notification
{
[WebView stopLoading];
NSURL * signOutUrl = (NSURL*)[notification objectForKey:#"RECEIVED_URL"];
[self loadURL:nil withURL:signOutUrl];
}

How to start and stop CMMotionManager startAccelerating and stopAccelerating while iphone in accelerate mode or in idle mode?

I am developing app related to accelerating. I'm using CMMtionManager object. but when I call startaccelerating method its working and continuously calling that method even iphone in idle mode. How to stop and start accelerating while iphone accelerating and idle.
- (void)viewDidLoad
{
[super viewDidLoad];
motionManager=[[CMMotionManager alloc]init];
motionManager.accelerometerUpdateInterval=2;
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self startMyMotionDetect];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[motionManager stopAccelerometerUpdates];
// Request to stop receiving accelerometer events and turn off accelerometer
}
- (CMMotionManager *)motionManager
{
motionManager = nil;
id appDelegate = [UIApplication sharedApplication].delegate;
if ([appDelegate respondsToSelector:#selector(motionManager)]) {
motionManager = [appDelegate motionManager];
}
return motionManager;
}
- (void)startMyMotionDetect
{ NSLog(#"active %d",motionManager.accelerometerActive);
NSLog(#"availabilty %d",motionManager.accelerometerAvailable);
[motionManager
startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc] init]
withHandler:^(CMAccelerometerData *data, NSError *error)
{
dispatch_async(dispatch_get_main_queue(),
^{
NSLog(#"hello");
[motionManager stopAccelerometerUpdates];
});
}];
}
please assist me.
did you try to add this?:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(stopAccelerometer)
name:UIApplicationDidEnterBackgroundNotification
object:nil];

NSnotifiaction doubts

I have a UISwitchcontroller in my setting page to change the image in main page. So I put a notification from setting page to main page. But only one notification I active every time, my setting page switch code look like this:
-(IBAction)_clickswitchlowlight:(id)sender
{
if(switchControll.on){
[switchControll setOn:YES animated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIF_lowlighton object:nil];
}
else{
[switchControll setOn:NO animated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIF_lowlightoff object:nil];
}
}
In my main page.h..I write this code:
extern NSString * const NOTIF_lowlighton;
extern NSString * const NOTIF_lowlightoff;
In .m above the implementation of main page I write this:
NSString * const NOTIF_lowlighton = #"lowlighton";
NSString * const NOTIF_lowlightoff = #"lowlightoff";
In viewwillappear I write this code:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(clicklowlighton:) name:#"lowlighton" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(clicklowlightoff:) name:#"lowlightoff" object:nil];
}
Then this code for changing the image:
- (void)clicklowlighton:(NSNotification *)notif
{
[[self multiPageView] setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"bgipad"]]];
}
- (void)clicklowlightoff:(NSNotification *)notif
{
[[self multiPageView] setBackgroundColor:[UIColor colorWithPatternImage:[UIImage imageNamed:#"bglowlight#2x"]]];
}
I only get the clicklowlightoff notification, I didn't get the first notification...any missing in my code?
bind your function to event: UIControlEventValueChanged to this function
-(IBAction)_clickswitchlowlight:(id)sender
{
if(switchControll.on){
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIF_lowlighton object:nil];
}
else{
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIF_lowlightoff object:nil];
}
}

Keyboard and getting up state on iPhone

How do I find out if the keyboard is up?
I have a UISearchbar instance which becomes the first responder.
When the keyboard appears a notification is sent out as part of the API, however I don't want to respond to this right away. I could record this in a boolean state, but that seems clunky. I'd like to know if there is a "getter" some where I can call to find out.
This is how I do it:
KeyboardStateListener.h
#interface KeyboardStateListener : NSObject {
BOOL _isVisible;
}
+ (KeyboardStateListener *) sharedInstance;
#property (nonatomic, readonly, getter=isVisible) BOOL visible;
#end
KeyboardStateListener.m
#import "KeyboardStateListener.h"
static KeyboardStateListener *sharedObj;
#implementation KeyboardStateListener
+ (KeyboardStateListener *)sharedInstance
{
return sharedObj;
}
+ (void)load
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
sharedObj = [[self alloc] init];
[pool release];
}
- (BOOL)isVisible
{
return _isVisible;
}
- (void)didShow
{
_isVisible = YES;
}
- (void)didHide
{
_isVisible = NO;
}
- (id)init
{
if ((self = [super init])) {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(didShow) name:UIKeyboardDidShowNotification object:nil];
[center addObserver:self selector:#selector(didHide) name:UIKeyboardWillHideNotification object:nil];
}
return self;
}
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
#end
Then use this to figure out the rest:
KeyboardStateListener *obj = [KeyboardStateListener sharedInstance];
if ([obj isVisible]) {
//Keyboard is up
}
The only sure way that I can think to do it as you said. using notifications like this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
and then
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
Other than that, you may be able to iterate through your views subviews and look for the keyboard like:
UIView *keyboard = nil;
for (UIView *potentialKeyboard in [myWindow subviews]) {
// iOS 4
if ([[potentialKeyboard description] hasPrefix:#"<UIPeripheralHostView"]) {
potentialKeyboard = [[potentialKeyboard subviews] objectAtIndex:0];
}
if ([[potentialKeyboard description] hasPrefix:#"<UIKeyboard"]) {
keyboard = potentialKeyboard;
break;
}
}
But I am not sure if this will break when the SDK changes ...
Maybe use this method and add a category to the window so that you can just always ask the window for the keyboard ... just a thought.

How to check for request time out , is there a notification I can set?

I want to check for whether the request has timed out after some period.
I know NSNotifiactionCenter ,but don't know how to set the request time out notification for it.
thanks.
You could just use a timer and cancel your notification request if not received by then?
e.g. taking Apple's reachability example:
- (void) startNotifier
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onReachabilityChanged:) name:#"kNetworkReachabilityChangedNotification" object:nil];
notified = NO;
[self performSelector:#selector(onRequestTimeout) withObject:nil afterDelay:5.0]; // 5 secs
}
- (void)onReachabilityChanged:(NSNotification *)note
{
// Do whatever on notification
notified = YES;
}
- (void) onRequestTimeout
{
if (!notified)
{
// Do whatever on request timeout
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"kNetworkReachabilityChangedNotification" object:nil];
}
}