This question already has answers here:
Release a NSMutableArray when using ARC
(2 answers)
Closed 9 years ago.
I have a string that I generate with JSON data from an URL
NSString *strResult = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
This code is inside viewDidLoad method. I want to release the string before I exit the method to avoid any memory leak, and I do this according to this post.
[strResult release];
However, xCode does not allow me by giving error: ARC forbids explicit send message of 'release'.
Anybody knows why? I tried to google it but no luck. I am new to iOS programming, and I have tried to google it before I asked. So any help will be appreciated.
ARC automatically adds the methods to deallocate objects, at compile time, for you.
Related
This question already has answers here:
convert NSTaggedPointerString to NSString
(5 answers)
Closed 6 years ago.
It's about a Get network request, for more information please see this pic.
I want to get the argument "pilotCode", but its value is "0xa00006e....", I want to get its real value which is "admin", please tell me what should I do?
Thank you very much.
I solved this problem just now.
just add this code:
"NSString *realStr = [NSString stringWithString:pilotCode];"
This question already has answers here:
How to fill NSArray in compile time?
(4 answers)
Closed 8 years ago.
If I initialize an NSArray as follows:
- (void) myMethod
{
NSArray *array = [NSArray arrayWithObjects:#"A","B","C",nil];
// DO SOME STUFF HERE
return;
}
Is this immutable array initialized at compile time or at run time? Same with NSDictionary. I'm thinking it must be at compile time but just wondering.
No… It would not be created in compile time… It would be created in runtime when the Method is being called.
By Immutability, it means that You cannot edit size of the array after once initializing it.
refer to this Link for more info about Object Mutability… Let me know if more info needed.. :)
Following code is what you want?
static NSString *strArray[] = {#"A", #"B", #"C"};
To use it with index like this: stringArray[index];
No, Method call arrayWithObjects: is not possible at compile time. During compilation, it just check that syntax, unless that variable would be constants or statics. Macros and constants are initialized at compile time. See this example below.
You could initialize directly, if the size is known as below(same example also posted by #simalone)
int num[5] = {2,8,7,6,0};
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
-[__NSCFDictionary JSONRepresentation]: unrecognized selector sent to instance
I use SBJson ( http://stig.github.com/json-framework/ ) in two of my project. Therefore I downloaded the code and copied it into my first project so that I can do something like this
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setValue:email forKey:#"email"];
[dict setValue:password forKey:#"password"];
NSString* json = [dict JSONRepresentation];
Now for my second and new project I did the same. I copied all the source files from SBJson into my new project and used the exact same code as above. But now when the program comes to line NSString* json = [dict JSONRepresentation]; I get the following error message:
-[__NSCFDictionary JSONRepresentation]: unrecognized selector sent to instance 0x689c710
What am I doing wrong in my second project?
Make sure that all the files have been added to the target.
Since iOS 5 you don't need an external library to use JSON, This tutorial could help you with that.
That error is because you are telling to dict, which is an instance of NSMutableDictionary, to perform a method called JSONRepresentation. dict doesn't know how to do that. I haven't work with that library but I would guess that you need to make an instance of SBJSON parser and then send dict as parameter. I found this and this tutorials, I hope they can help you.
I've written the following code:
NSString *string = [[NSString alloc] initWithFormat:#"test"];
[string release];
NSLog(#"string lenght = %d", [string length]);
//Why I don't get EXC_BAD_ACCESS at this point?
I should, it should be released. The retainCount should be 0 after last release, so why is it not?
P.S.
I am using latest XCode.
Update:
NSString *string = [[NSString alloc] initWithFormat:#"test"];
NSLog(#"retainCount before = %d", [string retainCount]);// => 1
[string release];
NSLog(#"retainCount after = %d", [string retainCount]);// => 1 Why!?
In this case, the frameworks are likely returning the literal #"test" from NSString *string = [[NSString alloc] initWithFormat:#"test"];. That is, it determines the literal may be reused, and reuses it in this context. After all, the input matches the output.
However, you should not rely on these internal optimizations in your programs -- just stick with the reference counting rules and well-defined behavior.
Update
David's comment caused me to look into this. On the system I tested, NSString *string = [[NSString alloc] initWithFormat:#"test"]; returns a new object. Your program messages an object which should have been released, and is not eligible for the immortal string status.
Your program still falls into undefined territory, and happens to appear to give the correct results in some cases only as an artifact of implementation details -- or just purely coincidence. As David pointed out, adding 'stuff' between the release and the log can cause string to really be destroyed and potentially reused. If you really want to know why this all works, you could read the objc runtime sources or crawl through the runtime's assembly as it executes. Some of it may have an explanation (runtime implementation details), and some of it is purely coincidence.
Doing things to a released object is an undefined behavior. Meaning - sometimes you get away with it, sometimes it crashes, sometimes it crashes a minute later in a completely different spot, sometimes a variable ten files away gets mysteriously modified.
To catch those issues, use the NSZombie technique. Look it up. That, and some coding discipline.
This time, you got away because the freed up memory hasn't been overwritten by anything yet. The memory that string points at still contains the bytes of a string object with the right length. Some time later, something else will be there, or the memory address won't be valid anymore. And there's no telling when this happens.
Sending messages to nil objects is, however, legitimate. That's a defined behavior in Objective C, in fact - nothing happens, 0 or nil is returned.
Update:
Ok. I'm tired and didn't read your question carefully enough.
The reason you are not crashing is pure luck. At first I though that you were using initWithString: in which case all the answers (including my original one (below)) about string literals would be valid.
What I mean by "pure luck"
The reason this works is just that the object is released but your pointer still points to where it used to be and the memory is not overwritten before you read it again. So when you access the variable you read from the untouched memory which means that you get a valid object back. Doing the above is VERY dangerous and will eventually cause a crash in the future!
If you start creating more object in between the release and the log then there is a chance that one of them will use the same memory as your string had and then you would crash when trying to read the old memory.
It is even so fragile that calling log twice in a row will cause a crash.
Original answer:
String literals never get released!
Take a look at my answer for this question for a description of why this is.
This answer also has a good explanation.
One possible explanation: You're superfluously dynamically allocating a string instead of just using the constant. Probably Cocoa already knows that's just a waste of memory (if you're not creating a mutable string), so it maybe releases the allocated object and returns the constant string instead. And on a constant string, release and retain have no effect.
To prove this, it's worth comparing the returned pointer to the constant string itself:
int main()
{
NSString *s = #"Hello World!";
NSString *t = [[NSString alloc] initWithFormat:s];
if (s == t)
NSLog(#"Strings are the same");
else
NSLog(#"Not the same; another instance was allocated");
return 0;
}
I am currently trying to integrate Paypal's MECL in an already existing IOS project using ARC.
I believe that by manually removing all the release / retain in the code should make it ARC compatible.
There is only one statement I do not know how to convert: "InitAndDealloc" that can be find in several class such as here:
static NSString *SolutionTypeStrings[] = {#"Sole", #"Mark"};
static NSString *LandingPageTypeStrings[] = {#"LandingPage", #"Billing", #"Login"};
static NSString *ChannelTypeStrings[] = {#"Merchant", #"eBayItem"};
#define LOCALE_CODE #"LocaleCode"
#implementation SetExpressCheckoutRequestDetails
InitAndDealloc
StringAccessor(ReturnURL)
StringAccessor(CancelURL)
StringAccessor1(cppHeaderImage, #"cpp-header-image")
StringAccessor1(cppHeaderBorderColor, #"cpp-header-border-color")
StringAccessor1(cppHeaderBackColor, #"cpp-header-back-color")
StringAccessor1(cppPayflowColor, #"cpp-payflow-color")
IntAccessor(AllowNote)
IntAccessor(ReqConfirmShipping)
TypedefAccessor(NoShipping, NoShippingType)
StringAccessor(Token)
AmountAccessor(MaxAmount)
StringAccessor(CallbackURL)
IntAccessor(CallbackTimeout)
GenericAccessor1(FlatRateShippingOptions, ShippingOptions)
IntAccessor(AddressOverride)
StringAccessor(PageStyle)
StringAccessor(BuyerEmail)
StringAccessor(giropaySuccessURL)
StringAccessor(giropayCancelURL)
StringAccessor(BanktxnPendingURL)
GenericAccessor(EnhancedCheckoutData)
GenericAccessor(BuyerDetails)
StringAccessor(BrandName)
GenericAccessor(FundingSourceDetails)
StringAccessor(CustomerServiceNumber)
IntAccessor(GiftMessageEnable)
IntAccessor(GiftReceiptEnable)
IntAccessor(GiftWrapEnable)
StringAccessor(GiftWrapName)
AmountAccessor(GiftWrapAmount)
IntAccessor(BuyerEmailOptinEnable)
StringAccessor(SurveyQuestion)
StringAccessor(CallbackVersion)
IntAccessor(SurveyEnable)
MutableArrayAccessor(PaymentDetails)
MutableArrayAccessor(BillingAgreementDetails)
MutableArrayAccessor1(OtherPaymentMethods, OtherPaymentMethodDetails)
MutableArrayAccessor1(SurveyChoice, NSString)
EnumAccessor(SolutionType, SolutionType)
EnumAccessor(LandingPage, LandingPageType);
EnumAccessor(ChannelType, ChannelType);
If I remove the line "InitAndDealloc", it seems as if I cannot set the variables anymore in the class. Indeed, I have also the working (Non ARC) paypal demo.
By doing this:
SetExpressCheckoutRequestDetails *sreq = [[SetExpressCheckoutRequestDetails alloc] init];
sreq.ReturnURL = #"Bob";
NSLog(#"%# ", sreq.ReturnURL );
In both projects.
Mine will return null, paypal's will return the Bob.
Has it even got anything to do with "InitAndDealloc" or am I looking at it wrong? If it is how do I replace "InitAndDealloc" in an ARC project? I can't seem to find a simple "Init" with autocompletion and by googling "InitAndDealloc" I get absolutely no results whatsoever :/
Thanks for reading!
I've never used MECL before but the way it's being called "InitAndDealloc" certainly is not Objective C and therefore wouldn't be subject to the same rules that ARC requires for Objective C. Best to leave it in place and not try to futz or struggle with it.
But anyways, instead of struggling with trying to ARC-enable some published & potentially-problematic SDK code, why not turn ARC off for the MECL files?
Here is a related question that describes how to turn ARC off for individual files.