How to deal with this NSString correctly with cocos2d? - objective-c

I'm new with cocos2d so i've got a problem with my In-App Purchase Class Helper. I wrote game in Cocoa Touch and this class working perfectly, but i'm writing now the same game in Cocos2d and problem is with NSString.
Here are some snippets.
This method is called as first when i clicked some button. As you see completeIdentifier is simple string with bundleIdentifier and some string parameter. It's ok, in this place i can log this completeIdentifier.
- (void)prepareToPurchaseItemWithIdentifier:(NSString *)aIdentifier showAlertWithTitle:(NSString *)title description:(NSString *)description delegate:(id)aDelegate{
self.delegate = aDelegate;
identifier = aIdentifier;
completeIdentifier = [NSString stringWithFormat:#"%#.%#", [[NSBundle mainBundle] bundleIdentifier], aIdentifier];
askToPurchase = [[UIAlertView alloc] initWithTitle:title message:description delegate:self cancelButtonTitle:nil otherButtonTitles:#"Later", #"Yes", nil];
askToPurchase.delegate = self;
[askToPurchase show];
}
Next method is UIAlertViewDelegate method. Is called when i click YES on alertView from first method.
#pragma mark - UIAlertViewDelegate Methods
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"%#", completeIdentifier);
if (alertView == askToPurchase) {
NSLog(#"[TSIAPHelper] Clicked YES. Prepare...");
if ([SKPaymentQueue canMakePayments]) {
NSLog(#"[TSIAPHelper] Prepare to purchase [%#].",completeIdentifier);
SKProductsRequest *request =[[SKProductsRequest alloc] initWithProductIdentifiers:
[NSSet setWithObject:completeIdentifier]];
request.delegate = self;
[request start];
pleaseWait = [[UIAlertView alloc] initWithTitle:#"Please wait..." message:#"" delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[activity startAnimating];
[pleaseWait addSubview:activity];
activity.frame = CGRectMake(125, 50, 36, 36);
[pleaseWait show];
}
else {
NSLog(#"[TSIAPHelper] Purchase [FAILURE]. Prohibited by Parentar Control or something like that.");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Prohibited." message:#"Parental Control is enabled, cannot make a purchase. Turn off and try again." delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alert show];
}
}
}
The problem is: Whenever and anywhere i want to Log variable completeIdentifier i've got crash with selected line: 0x39e965d0: ldr r3, [r4, #8] but i don't know what's that mean. And this line is selected:
NSLog(#"%#", completeIdentifier);
How can i fix it? In Cocoa Touch is working perfectly. When i use cocos2d isn't.

I guess you aren't using ARC. In this case completeIdentifier will be autoreleased.
Cocos2d clears the autoreleasepool every frame, whereas in Cocoa this is not strictly defined but may still crash. You can fix this by retaining or copying the string.
completeIdentifier = [NSString stringWithFormat:#"%#.%#", [[NSBundle mainBundle] bundleIdentifier], aIdentifier];
completeIdenfitier = [completeIdentifier retain];

Related

Adding NSData attachment to Twitter as an image post

Currently my app gives the option to save to device, or email, the latter attaching the image automatically to the mail, I am looking to add a post to twitter option, simply attaching the image and posting to Twitter, I have done this a few times with other apps, but cannot seem to get this one working.
Here is the process for email;
-(void)displayComposerSheet
{
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
mail.mailComposeDelegate = self;
[mail setSubject:#""];
NSString* path =[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/email.png"];
[mSplashView SaveResultImage:path];
[mail addAttachmentData:[NSData dataWithContentsOfFile:path] mimeType:#"image/png" fileName:#"Attached image"];
NSString *msg = [NSString stringWithFormat:#"I made this image!", [UIDevice currentDevice].model];
NSString* mailcontent = [NSString stringWithFormat:#"<br> %# <br>", msg];
[mail setMessageBody:mailcontent isHTML:YES];
[self presentModalViewController:mail animated:YES];
[mail release];
}
I am struggling to see how I can use similar to attach the image to Twitter, I currently use this code, but it crashes when attempting to post;
TWTweetComposeViewController *twitter = [[TWTweetComposeViewController alloc] init];
[self presentViewController:twitter animated:YES completion:nil];
NSString* path =[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/email.png"];
[mSplashView SaveResultImage:path];
[twitter setInitialText:#"I made this image!"];
[twitter addURL:[NSData dataWithContentsOfFile:path]];
twitter.completionHandler = ^(TWTweetComposeViewControllerResult res) {
if(res == TWTweetComposeViewControllerResultDone) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Thank you" message:#"Posted successfully to Twitter." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}
if(res == TWTweetComposeViewControllerResultCancelled) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Cancelled" message:#"You Cancelled posting the Tweet." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}
[self dismissViewControllerAnimated:YES completion:nil];
};
}
Normally I could simply call [twitter addImage:]; but unfortunately it seems the image is not grabbed correctly without going through the processes above in the mail sheet.
You can't pass NSData for -addURL: method.
If your image store on disk, you can create image with [UIImage imageWithContentsOfFile:imagePath] method. Next add it with -addImage:
NSString* path =[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/imgtweet.png"];
[UIImagePNGRepresentation(imageView.image) writeToFile:path atomically:YES];
//NSLog(#"path %#",path);
UIImage *new_image = [UIImage imageWithContentsOfFile:path];
if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter])
{
SLComposeViewController *tweetSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[tweetSheet setInitialText:self.txtContent.text];
[tweetSheet addImage:new_image];
[self presentViewController:tweetSheet animated:YES completion:nil];
}
Using Previous Answer,Thanks :)
Happy coding :)

error: address doesn't contain a section that points to a section in a object file

Hi i have searched here on the forum but no help found so i am posting it new. Here is the scenario, i am creating a mfmailcomposeviewcontroller in the main rootviewcontroller, i am displaying it by calling presentviewcontroller but when it is dismissed i get this error :
error: address doesn't contain a section that points to a section in a object file
The code i am using is given below:
-(void) mailButtonTapped
{
if ([MFMailComposeViewController canSendMail]) {
mailViewController_ = [[MFMailComposeViewController alloc] init];
mailViewController_.mailComposeDelegate = self;
[mailViewController_ setSubject:#"Try ..."];
[mailViewController_ setMessageBody:#"Hey I just tried ..." isHTML:NO];
NSData *videoData = [NSData dataWithContentsOfURL:movieURL_];
[mailViewController_ addAttachmentData:videoData mimeType:#"video/quicktime" fileName:#"Video.mov"];
[self presentViewController:mailViewController_ animated:YES completion:nil];
}
else {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Sharing Not Possible" message:#"Configure your mail to send the mail" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alertView show];
[alertView release];
}
}
-(void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
{
NSString *title = #"Email";
NSString *msg = nil;
if (result == MFMailComposeResultFailed)
msg = #"Unable to send, check your email settings";
else if (result == MFMailComposeResultSent)
msg = #"Email Sent Successfully!";
else if (result == MFMailComposeResultCancelled || result == MFMailComposeResultSaved)
msg = #"Sending Cancelled";
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
[alertView release];
[self dismissViewControllerAnimated:YES completion:nil];
}
After dismissing i receive the error:
error: address doesn't contain a section that points to a section in a object file
Please help me
I also had this error but with another scenario. I had a block property defined with #property (assign, nonatomic).
To fix this issue, I declared my block property with #property (copy, nonatomic).
Cheers
This error happens when an object / pointer is being accessed that doesn't exist anymore . And can also cause other bad access, 0x00000 value accessed etc.. errors.
So you are deleting/releasing a pointer , and then accessing later .
From looking at the code, and this is just a guess without debugging, you set the second AlertView's delegate to self, but then immediately dismiss the viewcontroller.
Try dismissing after the alert view is dismissed or the button is pressed, or maybe just setting the AlertView delegate to nil.
Even if that's not exactly the error, the main reason is somewhere you are releasing an object then trying to call a function or access it.
You can use it like this:
MFMailComposeViewController *mailViewController_ = [[MFMailComposeViewController alloc] init];
mailViewController_.mailComposeDelegate = self;
[mailViewController_ setSubject:#"Try ..."];
[mailViewController_ setMessageBody:#"Hey I just tried ..." isHTML:NO];
NSData *videoData = [NSData dataWithContentsOfURL:movieURL_];
[mailViewController_ addAttachmentData:videoData mimeType:#"video/quicktime" fileName:#"Video.mov"];
[self presentViewController:mailViewController_ animated:YES completion:nil];
[mailViewController_ release];
I also had this problem but caused by a very silly error, i wrote a property called frameon a class that inherits from UIView (it was a UITableViewCell but i think this would happen with every class that inherits from UIView) this overwrote the original frame property and caused this error.
Fixed just by changing property name.
The completion expects a block to be called when the animation of dismissal is completed.
Just remove "completion:nil" and it should work!
Regards.

UIActivityViewController dismiss MailViewController

I've try to send an email over the UIActivityViewController and it works fine, but the mail view is not dismissed after the email was send. It also wont't dismiss when the user has pushed the Cancel button.
What can I do to fix the problem?
Here the code I have used:
//conf share view
NSString *textToShare = #"Teststring!";
UIImage *imageToShare = fetchedImage;
NSURL *urlToShare = [NSURL URLWithString:string_url];
NSArray *activityItems = [[NSArray alloc] initWithObjects:textToShare, imageToShare,urlToShare,nil];
UIActivity *activity = [[UIActivity alloc] init];
NSArray *applicationActivities = [[NSArray alloc] initWithObjects:activity, nil];
UIActivityViewController *activityVC =
[[UIActivityViewController alloc] initWithActivityItems:activityItems
applicationActivities:applicationActivities];
activityVC.excludedActivityTypes = #[UIActivityTypeAssignToContact,
UIActivityTypePostToWeibo,
UIActivityTypeCopyToPasteboard,
UIActivityTypeSaveToCameraRoll,
UIActivityTypePrint];
[activityVC setCompletionHandler:^(NSString *activityType, BOOL completed) {
NSLog(#"CompletionHandler was called!");
}];
Thanks!
I have the solution. You want to present the UIActivityViewController in your fundamental, i.e. your highest or last view controller. In my case, this worked:
[[[self parentViewController] parentViewController] presentViewController:activityViewController animated:YES completion:nil];
Try out yourself how many times you have to call parentViewController until you are accessing the highest view controller. In my simple MasterView/DetailView app, I had to call it twice.
it always come in this completion handler after the posting is done weather it was successfull or not
[activityViewController setCompletionHandler:^(NSString *activityType, BOOL completed)
{
if (completed)
{
UIAlertView *objalert = [[UIAlertView alloc]initWithTitle:#"Alert" message:#"Posting was successful" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[objalert show];
objalert = nil;
}else
{
UIAlertView *objalert = [[UIAlertView alloc]initWithTitle:#"Alert" message:#"Posting was not successful" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[objalert show];
objalert = nil;
}
}];
then try to dismiss it on the completitionHandler
[activityVC setCompletionHandler:^(NSString *activityType, BOOL completed) {
//Dismiss here
}];

Two UIAlertView consecutively in didFinishLaunchingWithOptions

I want two alert views to show up only when the user opens my application for the first time -- the second to appear after the first is dismissed. I have it set up to only show the UIAlertViews when it has not been shown before and I do not need help with this. I need help figuring out how to display two alert views in a row when this is the case.
-(void) alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex does not work for me.
Here is the code I have -- remember this is in didFinishLaunchingWithOptions:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL didFirstLaunch = [defaults boolForKey:#"DidFirstLaunch"];
if (!didFirstLaunch) {
[defaults setBool:YES forKey:#"DidFirstLaunch"];
UIAlertView *successAlert = //not important
[successAlert show];
[successAlert release];
//Somehow show second alert after the first is dismissed
}
I'm gonna post a very simple solution using GCD & blocks (GCD part is just in case the alert view is created on another thread then the main thread, callback should be safe to perform on the main thread). Remember, I just coded this in like 5 mins, so you definitely should work on improving the code. One thing that's a bit ugly is the delegate parameter that is overridden in my subclass. The interface of the subclass could be changed a bit to make it more obvious of what happens ...
Anyway, here goes ...
First create a subclass of UIAlertView, make it look somewhat like the following ...
#interface FSAlertView () <UIAlertViewDelegate>
#property (nonatomic, copy) void (^dismissHandler)(NSInteger buttonIndex);
#end
#implementation FSAlertView
#synthesize dismissHandler = _dismissHandler;
- (void)showWithDismissHandler:(void (^)(NSInteger buttonIndex))dismissHandler
{
self.dismissHandler = dismissHandler;
self.delegate = self;
[self show];
}
// Alert view delegate
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
dispatch_async(dispatch_get_main_queue(), ^ {
if (_dismissHandler)
{
_dismissHandler(buttonIndex);
}
});
}
Now in the app we can create alert views like the following ...
FSAlertView *alert1 = [[FSAlertView alloc] initWithTitle:#"Alert 1"
message:#"Some message"
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Show 2nd Alert", nil];
[alert1 showWithDismissHandler:^ (NSInteger buttonIndex) {
NSLog(#"button pressed: %d", buttonIndex);
if (buttonIndex == 1)
{
UIAlertView *alert2 = [[UIAlertView alloc] initWithTitle:#"Alert 2"
message:#"Hi!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert2 show];
}
}];
If i understand your question correctly , then this may help:
UIAlertView *firstAlert = [[UIAlertView alloc] initWithTitle:#"Alert 1" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
[firstAlert show];
[self performSelector:#selector(test:) withObject:firstAlert afterDelay:2];
[firstAlert release];
UIAlertView *secondAlert = [[UIAlertView alloc] initWithTitle:#"Alert 2" message:nil delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
[secondAlert show];
[self performSelector:#selector(test:) withObject:secondAlert afterDelay:2];
[secondAlert release];
-(void)test:(UIAlertView*)alert{
[alert dismissWithClickedButtonIndex:-1 animated:YES];
}
This will show two alert views one after the other.
NOTE: I am not sure if you are dismissing the alerts with cancel button so i am dismissing them automatically after few seconds.
Try this:
UIAlertView *firstAlert = [[UIAlertView alloc] initWithTitle:#"Title" message:#"Message" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok", nil];
[firstAlert setTag:444];
[firstAlert show];
firstAlert = nil;
AlertView Delegate Method:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
switch (alertView.tag) {
case 444:
{
//Cancel ButtonIndex = 0
if (buttonIndex == 1) {
UIAlertView *secondAlert = [[UIAlertView alloc] initWithTitle:#"Title 2" message:#"Message2" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Dismiss", nil];
[secondAlert setTag:555];
[secondAlert show];
secondAlert = nil;
}
}
break;
case 555:
{
if (buttonIndex == 1) {
NSLog(#"Code Here");
}
}
break;
}
}

stop Saving Image to photo library

How to stop saving image. which is already exist in iphone photo library.
This code is for savingImage.....
-(IBAction)saveImage:(id)sender
{
NSLog(#"calling save");
if (coverPage !=nil)
{
NSData * imageData = UIImagePNGRepresentation(coverPage);
UIImage *theImage = [UIImage imageWithData:imageData];
UIImageWriteToSavedPhotosAlbum(theImage, self, nil, nil);
}
else {
UIAlertView *alertView =[[UIAlertView alloc] initWithTitle:#"Alert" message:#"Image is nil" delegate:self cancelButtonTitle:#"Cancle" otherButtonTitles:#"OK",nil];
[alertView show];
[alertView release];
}
}
if image is saved and clicking again and again the photo is saving..... How to stop saving image once it saved.
Without having more context it is difficult to say, but broadly speaking you can use a variable to track whether or not you have previously saved the current coverPage and simply avoid re-saving it if you have. For example:
-(IBAction)saveImage:(id)sender{
NSLog(#"calling save");
if (coverPageAlreadySaved) {
UIAlertView *alertView =[[UIAlertView alloc] initWithTitle:#"Alert" message:#"Silly user, you already saved this image." delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK",nil];
[alertView show];
[alertView release];
}
else if (coverPage !=nil) {
NSData * imageData = UIImagePNGRepresentation(coverPage);
UIImage *theImage = [UIImage imageWithData:imageData];
UIImageWriteToSavedPhotosAlbum(theImage, self, nil, nil);
coverPageAlreadySaved = YES;
}
else {
UIAlertView *alertView =[[UIAlertView alloc] initWithTitle:#"Alert" message:#"Image is nil" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK",nil];
[alertView show];
[alertView release];
}
}
...just be sure to set coverPageAlreadySaved = NO whenever the coverPage is changed (wherever you happen to be doing that in your code).
Alternately, since you already have the check against nil, you could just do:
-(IBAction)saveImage:(id)sender{
NSLog(#"calling save");
if (coverPage !=nil) {
NSData * imageData = UIImagePNGRepresentation(coverPage);
UIImage *theImage = [UIImage imageWithData:imageData];
UIImageWriteToSavedPhotosAlbum(theImage, self, nil, nil);
coverPage = nil;
}
else {
UIAlertView *alertView =[[UIAlertView alloc] initWithTitle:#"Alert" message:#"Image is nil" delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK",nil];
[alertView show];
[alertView release];
}
}
...which will prevent the image from being re-saved until it gets updated somewhere else in your code (at which point I assume it counts as a new coverPage).
If it's just one image you're saving then you can perform this just with a BOOL ivar for flag, like:
BOOL imageSaved;
And whenever you tap the button it'll just check if !imageSaved then perform the saving.
But if it's more then one image then you can do this using NSMutableArray.Like:
NSMutableArray *savedImages;//it's an ivar
Then before performing the saving operation:
NSString *imageName=......//Here I asssume you can get the image's name
if(!imageSaved)
NSMutableArray *savedImages=[[NSMutableArray alloc]init];
if (![savedImages containsObject:imageName]){
.........here comes the saving operation
and at the end you add the imageName to the array
[savedimages addObject:imageName];
}
I've given you just an example. You might not know the names of the images you save. If that's the case you can mark the image (which can be performed in several ways) and add the image itself.
Set the UIButton as an IBOutlet as well. Then set the enabled property to NO in the IBAction. Set the UIButton IBOutlet back to YES somewhere else in your program to 'reset' the button. It is similar to using a UIStepper in that you have to declare it twice...once as an IBAction and once as an IBOutlet.
This will allow you to use the button once, then it is 'greyed out' or 'muted' to prevent further activation. Basically you are disabling the UIGestureRecognizer from the UIButton.
Set the IBAction and IBOutlet.
- (IBAction)saveImageButton:(id)sender;
#property (weak, nonatomic) IBOutlet UIButton *saveImageButton;
Set the enabled to NO in the IBAction.
- (IBAction)saveImageButton:(id)sender {
UIImageWriteToSavedPhotosAlbum(_processedImageView.image, nil, nil, nil);
_saveImageButton.enabled = NO;
}
Then change it to YES somewhere else in your program to 'reset' the button so you can use it again.
_saveImageButton.enabled = YES;