I'm new to Objective C and I have a simple question about memory management.
This is a simple method for a Button which changes a UILabel with the text in a UITextField.
-(IBAction) setLabel
{
NSString *inputText = [[NSString alloc]initWithString:myTextField.text];
[myLabel setText:inputText];
[inputText release];
}
This code works fine. But If I change this code to following,
-(IBAction) setLabel
{
NSString *inputText = [[NSString alloc]initWithString:#"some string value"];
inputText = myTextField.text;
[myLabel setText:inputText];
[inputText release];
}
Then application crashes on runtime. I have to remove the line [inputText release]; to run application without crashing.
As far as I know if I created something with 'alloc' I have to release it. But here, if I release that string app crashes.Could someone please explain the reason?
Thanks in advance
The reason that the release is crashing is because you're reassigning inputText to myTextField.text. The call to release is now releasing that string instead of the one allocated on the first line of setLabel. If you use another variable for that assignment, it should fix the crash.
I know this is not a direct answer to your question but you should try to use the autorelease pool to not have to worry about these details. Thus, if you had written your code as follows:
-(IBAction) setLabel
{
NSString *inputText = [NSString stringWithString:myTextField.text];
[myLabel setText:inputText];
}
the code is more readable and, moreover, you are not responsible for releasing the inputText string instance.
Related
Appending new string to old string is causing crash.
(abnormally works if i do as like this StructIOS.server = #""; StructIOS.server = [StructIOS.server stringByAppendingString:#".stackoverflow.com"];).
struct.h:
struct iOS {
__unsafe_unretained NSString *input_url;
__unsafe_unretained NSString *use_url;
__unsafe_unretained NSString *server;
};
struct iOS StructIOS;
ViewController.m:
StructIOS.use_url = #"relay/pincode/apicode/accesskey/1/2/3/99/../900";
NSArray *work_array = [StructIOS.use_url componentsSeparatedByString:#"/"];
StructIOS.server = [work_array objectAtIndex:0];
if([StructIOS.server length] > 0) {
NSLog(#">>> 4: %#", StructIOS.server); // OK!!
StructIOS.server = [StructIOS.server stringByAppendingString:#".stackoverflow.com"]; // FAIL!!
NSLog(#">>> 5: %#", StructIOS.server);
}
Output:
>>> 4: relay
crash
Expected output:
>>> 5: relay.stackoverflow.com
EDIT: following way worked without crash
NSString *fool_ios;
// read from NSString type
StructIOS.server = fool_ios;
// save to NSString type
fool_ios = StructIOS.server;
The answer is two-fold:
Don't store objects in Objective-C Structs. ARC won't manage the memory for them.
Don't use unsafe_unretained unless you understand exactly what it does and exactly why you need it.
Simply make your variables instance variables of your class. That will make them strong, which is what you want.
EDIT:
Note that in Swift, it is valid to store objects in a Struct. Swift is able to memory manage them inside a struct, where C does not.
Any time the compiler forces you to use __unsafe_unretained, you're likely doing something wrong. (There are exceptions to that, but at your level of understanding, you should pretend that __unsafe_unretained doesn't exist.)
Why are they __unsafe_unretailed?
componentsSeparatedByString() will presumably internally be creating some substrings which you are not taking ownership of due to using __unsafe_unretained, thus they are being deleted when componentsSeparatedByString function got out of scope.
The log at line 4 is working purely though chance and good luck as the string is deallocated but still there at that memory location.
If you rewrite the struct as a simple class (which inherits from NSObject) it should work.
I am using an app to lock, unlock, and open the trunk of my car. The only problem is that I can't figure out how to modify the Xcode project so there are 3 buttons. Basically right now if I type "U" then enter- the car unlocks, "L" then enter- the car locks, and "T" then enter- the trunk opens. I want to add three buttons that simulate these three things and eliminate the typing all together. If you want to see my adruino or xcode project code I can upload those. I have put some code about the text box below.
BOOL)textFieldShouldReturn:(UITextField *)textField
{
NSString *text = textField.text;
NSNumber *form = [NSNumber numberWithBool:NO];
NSString *s;
NSData *d;
if (text.length > 16)
s = [text substringToIndex:16];
else
s = text;
d = [s dataUsingEncoding:NSUTF8StringEncoding];
if (bleShield.activePeripheral.state == CBPeripheralStateConnected) {
[bleShield write:d];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:text, TEXT_STR, form, FORM, nil];
[tableData addObject:dict];
[_tableView setContentOffset:CGPointMake(0, CGFLOAT_MAX)];
NSLog(#"%f", _tableView.contentOffset.y);
[self.tableView reloadData];
}
textField.text = #"";
return YES;
Thanks for the help!
Your view controller probably has a textFieldShouldReturn method which is taking the string value from the text field and building a parameter to a call that initiates sending the command. If not this method then perhaps its action method linked to the text field.
You'll need to duplicate parts of that code into a method that receives a string parameter instead of taking it from the text field, say named sendLockCommand:(NSString *)commandString (assuming you're coding in Objective-C, also like that repo).
Make action methods for your buttons, something like lockDoors, unlockDoors, openTrunk, in each call [self sendLockCommand:#"L"], each with the appropriate string. Wire up the buttons to those actions and you're good to go.
I'm learning to develop an IOS app. I'm having the following problem. I want to use a label to display a string. It takes a really long time for this string to be displayed (10-15 sec). Is this normal? The following code is inside the viewDidLoad function
NSLog(self.example); //displays almost immediately
_labelOutput.text= [NSString stringWithFormat:#"%#", self.example;//takes 15 seconds
The entire viewDidLoad function:
- (void)viewDidLoad
{
[super viewDidLoad];
double lat = 43.7000;
double lon = -79.4000;
NSArray *users = [[NSArray alloc] initWithObjects:#"user_1",#"user_2",#"user_3", nil];
id prediction = [[Prediction alloc] initWithUsers:users Lat:lat Lon:lon];
[prediction populate:^{
self.resName= [prediction generateRandom][#"id"];
NSLog([NSString stringWithFormat:#"%#", self.resName]);
_labelOutput.text= [NSString stringWithFormat:#"%#", self.resName];
}];
}
What does -[Prediction populate:] do with the block? My guess is it runs the block on a background thread or queue. You aren't allowed to modify the UI from a background thread or queue. Your app might crash or just act unpredictably. Your mysterious delay in updating the screen is a common symptom of this mistake.
You must only modify the UI from the main thread or queue. Try this:
[prediction populate:^{
self.resName= [prediction generateRandom][#"id"];
NSLog([NSString stringWithFormat:#"%#", self.resName]);
dispatch_async(dispatch_get_main_queue(), ^{
_labelOutput.text= [NSString stringWithFormat:#"%#", self.resName];
});
}];
ETA: Rob's answer is probably spot-on...if you'd posted that code initially I would have caught it as well.
Try setting the label's text in viewWillAppear or perhaps viewDidAppear instead.
Setting the "text" property of a label will normally trigger a [setNeedsDisplay] call automatically via key-value observing, and this notifies the system that the label's view needs to be redrawn on the next run loop. However, viewDidLoad is called before your view is actually visible. It's likely that because of this, either [setNeedsDisplay] is not being called, or is being ignored because the label is not yet visible...and thus, you have to wait for some other event to trigger re-drawing of subviews.
You could test this theory by adding a [self.labelOutput setNeedsDisplay] call yourself in viewDidAppear.
For swift 3 you'll want to use
DispatchQueue.main.async(execute: {
_labelOutput.LabelName.text = "Something"
})
I have one property say
#property(nonatomic,assign) NSString *str;
Now I am having something like
self.str = [[NSString alloc] init];
self.str = #"test";
NSLog(#"%#",str);
[self.str release];
When I run I can see a leak "Potential leak of memory".
Why its showing me leak ?
Please guide me I am leaning phase of iOS
In other words (I'm just expanding on Anoop's answer here), you have two strings, not one.
self.str = [[NSString alloc] init];
self.str = #"test";
The thing on the right side of the first line is a string: [[NSString alloc] init]. But in the second line you throw it away, replacing it with a different string, namely #"test". Now there is NO REFERENCE pointing to the first string. Thus it leaks, since it can never be released nor can anything else ever be done to or for it.
The situation of the string created in the first line is, after the second line, like the situation of "thing1" in the second panel of this diagram:
No one is pointing to it, so its memory cannot be managed, and it lives forever in isolation (leak).
self.str = [[NSString alloc] init]; //1st
One string is allocated not used.
self.str = #"test"; // 2nd
Another constant string "test" is allocated but released.
So first one is a leak.
When you use factory method or create object using alloc,new,retain,copy,mutableCopy your object has +1 retain count every time. You own object in this case. You are responsible for releasing it. So you need to release object after you finish using object which cause -1 retain count to object.
It is not necessary to alloc you string again as you are already creating its property.
And it has its getter setter + you are allocating it again so gives you a leak.
I want to know that difference between following two lines
name1 = [[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement,1)] retain];
name1 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement,1)];
What will be effect on name1 if I do use retain at the last,
I face once problem, and couldn't use name1 in a method that is being call by NSTimer, and when I use retain, they it worked fine for me.
If I do call value from database in viewDidLoad, and use in a method that is being called by NSTimer after each second, then it will give bad-exec, but when I do use retain then it will work properly,
I want to know the reason
Here is the difference
- (void)func1 {
name1 = [[NSString stringWithUTF8String:...] retain];
name2 = [NSString stringWithUTF8String:...];
}
- (void)func2 {
NSLog(#"%#", name1); //OK, name1 is still there
NSLog(#"%#", name2); //Would be crashed because name2 could be released anytime after func1 is finished.
}
I wrote this answer to another question, but it explains what you're asking:
Objects in objective c have a retain count. If this retain count is greater that 0 when the object goes out of scope (when you stop using it), it leaks.
The following things increase the retain count
[[alloc] init]
new
copy
[retain]
adding an object to an array
adding an object as a child (e.g. views)
There are likely more, but you don't appear to use any others in your code
The following decrease the retain count
[release]
removing an object from an array
if you dealloc an array, all of its objects are released
You should go through your code and ensure each of the retains or additions to an array are matched with a corresponding release. (You can release member variables in the dealloc method).
Another user made a valid point that my answer doesn't
Once you add an object to an array, it takes ownership and will release the object when it is done with it. All you need to do is make sure you release anything you own according to the memory management rules
There are also autorelease objects, have a look at this example;
-(init){
...
stagePickerArray = [[NSMutableArray alloc] init];
for (int i = 0; i < 3; i++)
{
//this string is autoreleased, you don't have call release on it.
//methods with the format [CLASS CLASSwithsomething] tend to be autorelease
NSString *s = [NSString stringWithFormat:#"%d", i);
[stagePickerArray addObject:s];
}
...
}
Your issue is that when you come to use your string later, it has a retain count of zero and has been released. By calling retain on it, you're saying 'I want to use this later'. Don't forget to match every retain with a release or you're objects will 'leak'
I bet your code wouldn't crash if your name1 was a property - either (nonatomic, retain) or just (copy) depending on your needs.
Second condition is to have name1 initialized to sth meaningful at the time your other function tries to do sth with it.
EDIT:
With a property you'd have to use synthesized setter in this case with: self.name1 = #"your string";.
Normally you don't have to manually retain/release a string created with stringWith... methods since there's nothing you created in memory yourself by using explicit alloc. Also please note that with code:
NSString *str = [NSString stringWithUTF8String:#"your string"];
your str (if not used to set a property) will stop being available when the function gets out of scope (iOS eventloop will autorelease it).