App crashes in Low network like(EDGE,100 %loss) - ios

My application implementing in-app purchase app crashes when connected to EDGE network, 100% loss,very poor network .There is no crash log. But it says "EXC BAD ACCESS code=1 address=0xc " on following line
_completionHandler(YES, skProducts);
Code for the method
#pragma mark - SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
sharedManager=[Mymanager sharedManager];
_productsRequest = nil;
sharedManager.bookidList=[[NSMutableArray alloc]init];
sharedManager.sharedProductPrice=[[NSMutableArray alloc]init];
NSArray * skProducts = response.products;
NSLog(#"sk product %#",skProducts);
// NSMutableArray *a=[[NSMutableArray alloc]init];
for (SKProduct * skProduct in skProducts) {
[sharedManager.sharedProductPrice addObject:skProduct.price];
[sharedManager.bookidList addObject:skProduct.productIdentifier];
}
[self updatePlist];
_completionHandler(YES, skProducts); //EXC BAD ACCESS CODE =1 ADDRESS=0XC
_completionHandler = nil;
}
I am following the in-app purchase tutorial on Ray Wenderlich's site (for iOS6.0). Minimum target of my application is iOS5. Any pointers how to fix this crash?
EDIT
New changes ,i made the NSArray to strong ARC property adn it still crashing check below images
tutorial
method to retrieve the product information from iTunes Connect:
- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler {
// 1
_completionHandler = [completionHandler copy];
// 2
_productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers];
_productsRequest.delegate = self;
[_productsRequest start];
}
This first squirrels a copy of the completion handler block inside the instance variable so it can notify the caller when the product request asynchronously completes.
It then creates a new instance of SKProductsRequest, which is the Apple-written class that contains the code to pull the info from iTunes Connect. It’s very easy to use – you just give it a delegate (that conforms to the SKProductsRequestDelegate protocol) and then call start to get things running.
We set the IAPHelper class itself as the delegate, which means that it will receive a callback when the products list completes (productsRequest:didReceiveResponse) or fails (request:didFailWithErorr).
Speaking of delegate callbacks, add those next! Add the following code before the #end:

It's quite likely that _completionHandler is nil when you are calling it in the method above. Attempting to execute a block variable when the variable is nil does give a bad access error.
You can confirm this by wrapping the execution of the completion handler block in an if statement and only executing it if the variable isn't nil:
if(_completionHandler)
{
_completionHandler(YES, skProducts);
}
Fixing the problem is another matter, you would need to trace the calls and see when the completion block is either not passed or removed.

Related

CallKit reinitializing causes com.apple.CallKit.error.requesttransaction Code=4 (UnknownCallUUID)

My iOS VoIP app uses CallKit in order to support native call integration feature. At first launch everything is working fine, but if I reinitialize CXProvider and CXCallController (in order to disable/enable feature), after incoming call hangup I receive error "com.apple.CallKit.error.requesttransaction Code=4".
#implementation CallKitHandler
- (void) configureCallKitWith
{
...
self.callKitProvider = [[CXProvider alloc] initWithConfiguration:_cxpConfiguration];
[_callKitProvider setDelegate:self queue:nil];
self.callKitCallController = [CXCallController new];
[_callKitCallController.callObserver setDelegate:self queue:nil];
...
}
- (void) requestEndCallActionWithCall:(Call*) callEnded
{
CXEndCallAction* endCallAction = [[CXEndCallAction alloc] initWithCallUUID:self.callUUId];
CXTransaction* transaction = [[CXTransaction alloc] initWithAction:endCallAction];
OTCLogVerbose (#"requestEndCallActionWithCall '%#' : %#", callEnded.reference, transaction);
[self.callKitCallController requestTransaction:transaction completion:^(NSError* error) {
if (error)
{
OTCLogWarn (#"requestEndCallActionWithCall failed for '%#': %#", _callUUId, [self errorDescriptionOf: error]);
I tried to make my CallKitHandler class as singleton, and it seems to be working, is it the only possible solution? Should you avoid reinitializing CallKit during app's runtime?
The documentation says:
A VoIP app should create only one instance of CXProvider and store it for use globally.
So, yes: you should avoid instantiating the CXProvider every time you want to reconfigure it. Just keep a global reference and reconfigure it if you need to.

How to retain variable in arc in every class

I have a lot of classes which are sending requests and finally it all comes to SplitViewController. In the SplitUIviewclass I have to long poll and write the data in a table view. The long polling is done in the background thread, so I have declared a variable in app delegate, but when it comes to that it is nil. And the problem is whenever I try to access the NSMutablearray through the appdelegate, its coming as nil and the array is being released. My code for long polling is
- (void) longPoll {
#autoreleasePool
{
//compose the request
NSError* error = nil;
NSURLResponse* response = nil;
NSURL* requestUrl = [NSURL URLWithString:#"http://www.example.com/pollUrl"];
NSURLRequest* request = [NSURLRequest requestWithURL:requestUrl];
//send the request (will block until a response comes back)
NSData* responseData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response error:&error];
//pass the response on to the handler (can also check for errors here, if you want)
[self performSelectorOnMainThread:#selector(dataReceived:)
withObject:responseData waitUntilDone:YES];
}
//send the next poll request
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) startPoll {
[self performSelectorInBackground:#selector(longPoll) withObject: nil];
}
- (void) dataReceived: (NSData*) theData {
//i write data received here to app delegate table
}
If I call any other method in my SplitView class from data received, I'm losing control, also I cannot print my app delegate values in data received or the variables being released, I cannot call reload table or any other method from here.
Cant you set your properties in your ViewControllers as strong/retain like so
property (strong,retain) NSMutableArray *myData;
BTW, I learned a moment ago that it is bad practise to use your AppDelegate as a storage place for global containers. The ApplicationDelegate is a place for application delegate methods and for the initial setup of the foundation of your app; such as setting up the navigationController.
So consider storing your data in the appropriate place, perhaps core data or something else.

What causes NSURLConnection to stop receiving before it's done?

My game needs to fill tableView cells with a bunch of things from my server database. This has been working fine. Then I upgraded Xcode to 4.6 and targeted iOS6.1, to please the App Review Team folks. Now, one of my connections never completes. (All of the other Posts seem to work correctly, as always.) Here's my post:
- (void) fillCells {
Cell_QtoA *newCell = [[Cell_QtoA alloc] initCellUser:usrID Grp:grpID Qtn:0 Gnm:#"na" Cat:#"na" Sit:#"na" Pfl:#"na" Lks:0 isA:0 ddA:0 ];
NSMutableURLRequest *reqPost = [SimplePost urlencodedRequestWithURL:[NSURL URLWithString:kFillCells] andDataDictionary:[newCell toDictC]];
(void) [[NSURLConnection alloc] initWithRequest:reqPost delegate:self];
}
I think it's working fine. The PHP and database haven't changed. Everything worked great yesterday, before the upgrades. Here's my connection method:
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"data = %#", data);
NSString *error;
NSArray *array = (NSArray *)[NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:0 errorDescription:&error];
if( error ) {
NSLog(#"Error = %#", error);
return;
}
NSLog(#"1st object in array of %d is %#", [array count], array );
}
Because I suspected net speeds to be an issue, I added a timer to the call, which I never needed before:
timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(fillCells) userInfo:nil repeats:YES];
The timer didn't help. Still get errors:
"Unexpected EOF" and "Unexpected character z (or whatever) at Line 1"
The NSLog of data shows hex data that appears cut off, like:
<3c3f786d 6c207665 ... 63743e0a 3c2f6172 7261793e 0a3c2f70 6c697374 3e>
It's like the reception is being interrupted. Anyone know what's happening here? Thanks!
You aren't using all the response data; as mention in the NSURLConnectionDelegate reference:
The newly available data. The delegate should concatenate the contents
of each data object delivered to build up the complete data for a URL
load.
So you need to create an NSData instance variable; clear before the request and append to it whenever new data arrives. Then use the didFinishLoading delegate method to trigger the call to propertyListFromData with the complete response.

RestKit connection failure delegate

I'm trying to test the behavior of my app when connection fails. I am testing on an iPad with wifi turned off. When Restkit attempts a web service call, I get the following error:
CPL[7713:6203] E restkit.network:RKRequest.m:545 Failed to send request to https://xxxxxxxx/APNS_WebService/rest/operations/initializeDevice?deviceID=c4a17f855d3cc824b174b71908480d4e505ebfb221cb4643da9270a07344c367 due to unreachable network.
The problem is that I would like to handle this situation in a delegate callback method, but none of the delegate methods are being called. I have set the delegate on the request, and have requestDidFailLoadWithError, requestDidCancelLoad, requestDidTimeout, and objectLoaderDidFailWithError implemented. None of these are called.
Why aren't my delegates being called?
EDIT: After setting a breakpoint inside RKRequest.m, I see that the following line is in fact being executed:
[self performSelector:#selector(didFailLoadWithError:) withObject:error afterDelay:0];
However, my delegate methods are not getting called.
Here's where I set the delegate:
request = [client requestWithResourcePath:[NSString stringWithFormat:#"/initializeDevice?deviceID=%#",deviceID]];
request.delegate=self;
[request sendAsynchronously];
EDIT 2: Actually, the line in RKRequest.m that I posted above is just calling another method in RKRequest, except that it's not. Putting a breakpoint in didFailLoadWithError shows that this code is never reached. I don't get why that's not working.
Changing the performSelector to a regular method call appears on the surface to give me the behavior I'm looking for. Is this going to break anything? I guess I'm not sure why performSelector is being used to call a method in the same class.
EDIT 3: As requested, here's my delegate method:
-(void)request:(RKRequest *)request didFailLoadWithError:(NSError *)error{
NSLog(error.domain);
NSLog([NSString stringWithFormat:#"%d",error.code]);
NSLog(error.localizedDescription);
NSLog(error.localizedFailureReason);
[request reset];
[request send];
}
EDIT:
Actually, the line in RKRequest.m that I posted above is just calling another method in RKRequest, except that it's not. Putting a breakpoint in didFailLoadWithError shows that this code is never reached. I don't get why that's not working.
This is really strange. I would try doing a full clean of the project and rebuild.
As to what entails a direct call instead of using performSelector, you can see that afterDelay:
[self performSelector:#selector(didFailLoadWithError:) withObject:error afterDelay:0];
this will make the didFailLoadWithError: method be called at the next iteration of the run loop. I would keep this way of calling it.
You could try, though, with this alternative:
dispatch_async(dispatch_get_current_queue(), ^() {
[self didFailLoadWithError:error]; } );
I would suggest setting a breakpoint inside of the RestKit method you are using (I suppose sendAsynchronously) and check what happens. If you look into the method definition, the call to the delegate is effectively there:
} else {
self.loading = YES;
RKLogError(#"Failed to send request to %# due to unreachable network. Reachability observer = %#", [[self URL] absoluteString], self.reachabilityObserver);
NSString* errorMessage = [NSString stringWithFormat:#"The client is unable to contact the resource at %#", [[self URL] absoluteString]];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
errorMessage, NSLocalizedDescriptionKey,
nil];
NSError* error = [NSError errorWithDomain:RKErrorDomain code:RKRequestBaseURLOfflineError userInfo:userInfo];
[self performSelector:#selector(didFailLoadWithError:) withObject:error afterDelay:0];
}

How to save data out of an iOS completion block

I'm basically implementing a fancier NSURLConnection class that downloads data from a server parses it into a dictionary, and returns an NSDictionary of the data. I'm trying add a completion block option (in addition to a delegate option), but it crashes anytime I try to store that data in another class.
[dataFetcher_ fetchDataWithURL:testURL completionHandler:^(NSDictionary *data, NSInteger error) {
contentDictionary_ = data;
}];
I can NSLog that data just fine, and basically do whatever I want with it, but as soon as I try to save it into another variable it crashes with a really obscure message.
EDIT: the crash message is EXC_BAD_ACCESS, but the stack trace is 0x00000000 error: address doesn't contain a section that points to a section in a object file.
I'm calling this function in the init method of a singleton. It DOES let me save the data if I set this in the completion block.
[SingletonClass sharedInstance].contentDictionary = data
But then the app gets stuck forever because sharedInstance hasn't returned yet, so the singleton object is still nil, so sharedInstance in the completion block calls init again, over and over.
EDIT 2: The singleton code looks like this:
+ (SingletonClass*)sharedInstance {
static SingletonClass *instance;
if (!instance) {
instance = [[SingletonClass alloc] init];
}
return instance;
}
- (id)init {
self = [super init];
if (self) {
dataFetcher_ = [[DataFetcher alloc] init];
NSString *testURL = #"..."
[dataFetcher_ fetchDataWithURL:testURL completionHandler:^(NSDictionary *data, NSInteger error) {
[SingletonClass sharedInstance].contentDictionary = data;
}];
}
return self;
}
Like I said, this works fine but repeats the initialize code over and over until the app crashes. This only happens the first time I run the app on a device, because I cache the data returned and it doesn't crash once I have the data cached. I would like to be able to just say self.contentDictionary = data, but that crashes.
Specify a variable to be used in the block with the __block directive outside of the block:
__block NSDictionary *contentDictionary_;
[dataFetcher_ fetchDataWithURL:testURL completionHandler:^(NSDictionary *data, NSInteger error) {
contentDictionary_ = data;
}];
You're invoking recursion before ever setting the "instance". (which I now see you understand from OP).
In your block, you can use the ivar or an accessor instead of
[SingletonClass sharedInstance].contentDictionary
use:
_contentDictionary = [data copy]; or self.contentDictionary=data;
assuming that the ivar backing the contentDictionary property is _contentDictionary.
It sounds like you tried self.contentDictionary and it failed? I got it to work in a test, with ARC turned, so there may be something about your dataFetcher that is affecting this. In my test dataFetcher just returns a dictionary with a single element.
Turns out the issue was with a bunch of different parts. My URL was empty sometimes, and my data fetcher would just fail immediately and call the completion block. In my completion block I hadn't included any error handling, so if the singleton class hadn't initialized, it would repeat forever. With a real URL this doesn't happen.
I still would like to figure out why it crashes when I try to assign the data to an ivar, though.

Resources