Here is code I am referring to.
// Person.h
#interface Person : NSObject {
NSString *firstName;
NSString *lastName;
}
#end
// Person.m
#implementation Person
- (id)init {
if (![super init]) return nil;
firstName = #"John";
lastName = #"Doe";
}
#end
// MyClass.m
#implementation MyClass
.....
- (NSArray *)getPeople {
NSMutableArray *array = [[NSMutableArray alloc] init];
int i;
for (i = 0; i < 10; i++) {
Person *p = [[Person alloc] init];
[array addObject:p];
}
return array;
}
.....
#end
Now, I know there is no memory-management going on in this sample code. What would be required?
In the getPeople loop, I am alloc'ing a Person (retainCount 1), then adding it to array. The retain count is now 2, right? If it is two, should I be [p release]'ing after adding it to the array, bringing the retainCount back down to 1?
Am I right in that it is the caller's responsibility to release the array returned by the method? (Which would also free the memory of the Person's, and their instance variables, assuming their counts are at 1).
I have read Apple's memory management document, but I guess what I am most unclear about, is what increases an objects retain count? I think I grasp the idea of who's responsibility it is to release, though. This is the fundamental rule, according to Apple:
You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.
bobDevil's sentence "only worry about the retain counts you add to the item explicitly" made it click for me. After reading the Ownership policy at Apple, essentially, the object/method that created the new object, is the one responsible for releasing /it's/ interest in it. Is this correct?
Now, let's say I a method, that receives an object, and assigns it to a instance variable. I need to retain the received object correct, as I still have an interest in it?
If any of this is incorrect, let me know.
You are correct that the retain count is 2 after adding it to an array. However, you should only worry about the retain counts you add to the item explicitly.
Retaining an object is a contract that says "I'm not done with you, don't go away." A basic rule of thumb (there are exceptions, but they are usually documented) is that you own the object when you alloc an object, or create a copy. This means you're given the object with a retain count of 1(not autoreleased). In those two cases, you should release it when you are done. Additionally, if you ever explicitly retain an object, you must release it.
So, to be specific to your example, when you create the Person, you have one retain count on it. You add it to an array (which does whatever with it, you don't care) and then you're done with the Person, so you release it:
Person *p = [[Person alloc] init]; //retain 1, for you
[array addObject:p]; //array deals with p however it wants
[p release]; //you're done, so release it
Also, as I said above, you only own the object during alloc or copy generally, so to be consistent with that on the other side of things, you should return the array autoreleased, so that the caller of the getPeople method does not own it.
return [array autorelease];
Edit:
Correct, if you create it, you must release it. If you invest interest in it (through retain) you must release it.
Retain counts are increased when you call alloc specifically, so you'll need to release that explicitly.
factory methods usually give you an autoreleased object (such as [NSMutableArray array] -- you would have to specifically retain this to keep it around for any length of time.).
As far as NSArray and NSMutableArray addObject:, someone else will have to comment. I believe that you treat a classes as black boxes in terms of how they handle their own memory management as a design pattern, so you would never explicitly release something that you have passed into NSArray. When it gets destroyed, its supposed to handle decrementing the retain count itself.
You can also get a somewhat implicit retain if you declare your ivars as properties like #property (retain) suchAndSuchIvar, and use #synthesize in your implementation. Synthesize basically creates setters and getters for you, and if you call out (retain) specifically, the setter is going to retain the object passed in to it. Its not always immediately obvious, because the setters can be structured like this:
Person fart = [[Person alloc] init];
fart.firstName = #"Josh"; // this is actually a setter, not accessing the ivar
// equivalent to [fart setFirstName: #"Josh"], such that
// retainCount++
Edit:
And as far as the memory management, as soon as you add the object to the array, you're done with it... so:
for (i = 0; i < 10; i++) {
Person *p = [[Person alloc] init];
[array addObject:p];
[p release];
}
Josh
You should generally /not/ be worried about the retain count. That's internally implemented. You should only care about whether you want to "own" an object by retaining it. In the code above, the array should own the object, not you (outside of the loop you don't even have reference to it except through the array). Because you own [[Person alloc] init], you then have to release it.
Thus
Person *p = [[Person alloc] init];
[array addObject:p];
[p release];
Also, the caller of "getPeople" should not own the array. This is the convention. You should autorelease it first.
NSMutableArray *array = [[[NSMutableArray alloc] init] autorelease];
You'll want to read Apple's documentation on memory management: http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
Related
Given the following simple implementation:
#implementation RTUDeallocLogger
-(void)dealloc
{
NSLog(#"deallocated");
}
#end
we run the following code under ARC:
#implementation RTURunner
{
NSArray* arr;
}
-(void)run{
arr = [NSArray
arrayWithObjects:[[RTUDeallocLogger alloc]init],
[[RTUDeallocLogger alloc]init],
[[RTUDeallocLogger alloc]init],
nil];
NSLog(#"nulling arr");
arr = NULL;
NSLog(#"finished nulling");
}
#end
we get the following log output:
nulling arr
finished nulling
deallocated
deallocated
deallocated
I'd like to perform an action after all the deallocations have finished. Is this possible?
The aim of this question is really to understand a little more about the mechanics of ARC, in particular, at what point ARC triggers these deallocations, and whether or not this can ever happen synchronously when I drop references.
-dealloc is always synchronous, and occurs when the last strong reference is removed. In the case of your code though, +arrayWithObjects: is likely (if compiled at -O0 at least) putting the array in the autorelease pool, so the last strong reference is removed when the pool drains, not when you set the variable to NULL (you should use nil for ObjC objects, btw).
You can likely avoid having the object in the autorelease pool by using alloc/init to create, and you may (implementation detail, bla bla) be able to avoid it by compiling with optimizations turned on. You can also use #autoreleasepool { } to introduce an inner pool and bound the lifetime that way.
If I were an engineer from Apple I'd probably argue that your problem is probably your design. There are almost no reasons you'd want effectively to act by watching dealloc rather than having dealloc itself act.
[a huge edit follows: weak properties don't go through the normal property mechanisms, so they aren't KVO compliant, including for internal implicit KVO as originally proposed]
That said, what you can do is bind the lifetime of two objects together via object associations and use the dealloc of the latter as a call-out on the dealloc of the former.
So, e.g.
#import <objc/runtime.h>
#interface DeallocNotifier;
- (id)initWithObject:(id)object target:(id)target action:(SEL)action;
#end
#implementation DeallocNotifier
- (id)initWithObject:(id)object target:(id)target action:(SEL)action
{
... blah ...
// we'll use a static int even though we'll never access by this key again
// to definitely ensure no potential collisions from lazy patterns
static int anyOldKeyWellNeverUseAgain;
objc_setAssociatedObject(object, &anyOldKeyWellNeverUseAgain, self, OBJC_ASSOCIATION_RETAIN);
... blah ...
}
- (void)dealloc
{
[_target performSelector:_action];
}
#end
-(void)run{
arr = ...
[[DeallocNotifier alloc]
initWithObject:arr target:self action:#selector(arrayDidDealloc)];
/* you may not even need *arr in this case; I'm unclear as
to why you have an instance variable for something you don't
want to keep, so I guess it'll depend on your code */
} // end of run
- (void)arrayDidDealloc
{
NSLog(#"array was deallocated");
}
I've assumed you're able to tie the lifecycle of all the objects you're interested in to that of a single container; otherwise you could associate the notifier to all relevant objects.
The array has definitely gone by the time you get arrayDidDealloc.
at what point ARC triggers these deallocations
ARC inserts allocations/deallocations into your code based on static analysis. You can see where it does this by looking at the assembly of your source -- go to Product -> Generate Output in Xcode.
whether or not this can ever happen synchronously when I drop references
Retain/release/autorelease is always synchronous.
Your code
arr = [NSArray arrayWithObjects:[[RTUDeallocLogger alloc] init],
[[RTUDeallocLogger alloc] init],
[[RTUDeallocLogger alloc] init],
nil];
will be implicitly placing the objects into an autorelease pool. After the object is allocated, you don't want it retained (because the NSArray will do the retain once it receives the object), but you can't release it immediately, otherwise it will never make it to the NSArray alive. This is the purpose of autorelease - to cover the case where the object would otherwise be in limbo between two owners.
The retain count at alloc time is 1, then it's retained by the autoreleasepool and released by you, so the retain count remains 1. Then, it's retained by the NSArray, so the retain count becomes 2.
Later, the NSArray is released and so the retain count returns to 1, and the objects are finally cleaned up when the autorelease pool gets its chance to run.
You can make the autorelease act faster by nesting another pool - by wrapping your NSArray creation with an #autorelease{} clause.
my.h file
#interface myObject : NSObject {
NSMutableDictionary *myDictn ;
}
i have a property
#property (nonatomic,retain) NSMutableDictionary *myDictn ;
then in .m File
i have a allocated it from id
- (id)init {
if (self=[super init]) {
myDictn= [NSMutableDictionary alloc]init];
}
}
my Question is i have mentioned Retain in Property and i have allocated memory also (is Retain Count goes to 2 in (id)init )
so how to manage memory in this case ?
i am new to this so dnt have much idea regarding memory management .
one more thing if i have a method x in my code and i also allocated memory to myDictn then in that case also how can i use release .??
Thanks in Advance .
The proper way to initialize a retained property is:
NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init];
self.myDictn = newDict;
[newDict release];
or alternatively:
self.myDict = [NSMutableDictionary dictionary];
The first method makes sure not to increase the already retained property's retain count by performing alloc,init (an action that increments retain count) on a temporary object.
The second method uses a convenience method for obtaining an autoreleased instance of the dictionary.
You should first refer to Cocoa Fundamentals Guide. Then, if you're targeting iOS > 4.3, you can rely on Automatic Reference Counting for memory management. But be sure to understand the base concepts and read the fundamental guide or you'll waste a lot of time programming in the dark.
I don't understand this one unless it's because I'm releasing the property instead of the ivar. Can someone shed light on the problem?
self.dataToBeLoaded = [[NSMutableData alloc] initWithLength:10000];
[self.dataToBeLoaded release];
The warning is Incorrect decrement of the reference count of an object that is not owned by the caller.
The dataToBeLoaded property has the retain attribute associated with its setter.
My understanding is the the alloc init increments the retain count and the property assignment increments the retain count. Since I only one to retain it once, that's why I release it immediately after the assignment.
UPDATE -- some experimental results:
Since I noted in my comments below that I have received contradictory advice on what the retain property does to the synthesized setter, I thought I would do a little experiment using the code above, modified with some logging:
NSLog(#"retain 1 = %d", [dataToBeLoaded_ retainCount]);
self.dataToBeLoaded = [[NSMutableData alloc] initWithLength:10000];
NSLog(#"retain 2 = %d", [dataToBeLoaded_ retainCount]);
[self.dataToBeLoaded release];
NSLog(#"retain 3 = %d", [dataToBeLoaded_ retainCount]);
The results at each log statement were 0, 2, and 1.
Apparently, it's not possible to step into the alloc or the init code to see the retain count go from 0 to 1 to 2. I could have subclassed the NSMutableData class, but I was short on time.
I know a lot is said that you can't rely on the value of the retainCount property, but what I have seems consistent and I would expect reasonable behavior over the short scope of the code like that shown in the example. So I'm inclined to believe that prior advice is correct -- the retain property is a promise to include a retain within the setter. So here I have the retain from the alloc/init and the retain from the call to the setter. Hence, the retain count is set to 2.
When I run this code:
NSMutableData *theData;
NSLog(#"retain 1 = %d", [theData retainCount]);
theData= [[NSMutableData alloc] initWithLength:10000];
NSLog(#"retain 1a = %d", [theData retainCount]);
self.dataToBeLoaded = theData;
NSLog(#"retain 2 = %d", [theData retainCount]);
[self.dataToBeLoaded release];
NSLog(#"retain 3 = %d", [theData retainCount]);
The retain count at each log statement is 0, 1, 2, 1.
So I have evidence that suggests the setter is providing a retain. This appear to be more of a promise than a hint, because it is actually happening.
I'm open to other explanations. I don't want to be arrogant about this. I just want to get it right as to what is happening. I appears that the warning (in the subject of this question) is really spurious and not something to worry about.
One more experiment is done using assign rather than retain as an attribute in the #property statement. With the same code:
NSMutableData *theData;
NSLog(#"retain 1 = %d", [theData retainCount]);
theData= [[NSMutableData alloc] initWithLength:10000];
NSLog(#"retain 1a = %d", [theData retainCount]);
self.dataToBeLoaded = theData;
NSLog(#"retain 2 = %d", [theData retainCount]);
[self.dataToBeLoaded release];
NSLog(#"retain 3 = %d", [theData retainCount]);
The retain count at each log is 0, 1, 1 (the setter did not retain), then the error message: message sent to deallocated instance. The last release had set the retain count to zero, which triggered the deallocation.
UPDATE 2
A final update -- when the synthesized setter is overridden with your own code, the retain attribute is no longer observed unless your setter explicitly includes it. Apparently (and this contradicts what I had been told in other threads here) you have to include your own retain in the setter if that's what you want. While I didn't test it here, you probably need to release the old instance first, or it will be leaked.
This custom setter no longer has the property attributes of the #propety declaration:
- (void) setDataToBeLoaded:(NSMutableData *)dataToBeLoaded {
dataToBeLoaded_ = dataToBeLoaded;
}
This makes sense. Override a synthesized setter and you override all of the declared properties. Use a synthesized setter, and the declared properties are observed in the synthesized implementation.
The #property attributes represent a "promise" as to how the synthesized setter is implemented. Once you write a custom setter, you're on your own.
The key is to think through what the below code is doing. I'll write it out in full for clarity:
[self setDataToBeLoaded:[[NSMutableData alloc] initWithLength:10000]];
This creates an object with a +1 retain count and passes it to setDataToBeLoaded:. (*) It then throws away its reference to that object, leaking it.
[[self dataToBeLoaded] release];
This calls dataToBeLoaded and releases the object returned. There is no promise whatsoever that the object returned by dataToBeLoaded is the same as the object passed to setDataToBeLoaded:. You probably think they're the same, and looking at your code you can probably convince yourself that it will always work out that way, but that's not an API promise.
The code posted by Antwan is correct:
NSMutableData *data = [[NSMutableData alloc] initWithLength:1000];
self.dataToBeLoaded = data;
[data release];
That creates an object with a +1 retain count. Then passes it to a method, then releases it.
Or, if you're willing to use the autorelease pool, you can simplify it to:
self.dataToBeLoaded = [NSMutableData dataWithLength:1000];
(*) Technically this passes a message to self that may or may not cause this method to be called, but that muddies the issue. For most purposes, pretend it's a method call. But do not pretend that it just sets the property. It really is going to call some method.
EDIT:
Maybe this code will make the issue a little clearer. It's indicative of common caching solutions:
.h
#interface MYObject : NSObject
#property (nonatomic, readwrite, strong) NSString *stuff;
#end
.m
#interface MYObject ()
#property (nonatomic, readwrite, weak) MYStuffManager *manager;
#implementation MYObject
... Initialize manager ...
- (NSString*)stuff {
return [self.manager stuffForObject:self];
}
- (void)setStuff:(NSString *)stuff {
[self.manager setStuff:stuff forObject:self];
}
Now maybe manager does some foolery in the background. Maybe it caches various copies of stuff. Maybe it copies them. Maybe it wraps them into other objects. What's important is that you can't rely on -stuff always returning the same object you passed to -setStuff:. So you certainly shouldn't release it.
Note that nothing in the header indicates this, and nothing should. It's not the callers' business. But if the caller releases the result of -stuff, then you will get hard-to-debug crashes.
#synthesize is just a shorthand for writing some tedious code (code that implements stuff and setStuff: as reading and writing an ivar). But nothing says that you have to use #synthesize for your properties.
My guess would be that the method
- (NSMutableData *)dataToBeLoaded;
does not contain any of the memory management keywords therefore it is assumed that you do not own the data returned and therefore should not be releasing it.
Either use
NSMutableData *data = [[NSMutableData alloc] initWithLength:1000];
self.dataToBeLoaded = data;
[data release]; data = nil;
or if you can why not lazy load it when you actually need it?
- (NSMutableData *)dataToBeLoaded;
{
if (!_dataToBeLoaded) {
_dataToBeLoaded = [[NSMutableData alloc] initWithLength:1000];
}
return _dataToBeLoaded;
}
It just means that you are releasing an object you don't own.
I'd say call it with the instance var directly instead of using the getter, but not sure whether that will fix your analyses warnings. Also why not use [NSMutableData dataWithLength:1000]; which is autoreleased and therefore eliminates the need of that extra release call ( and would probably get rid of that warning too! )
other ways you could fix it:
NSMutableData *data = [[NSMutableData alloc] initWithLength:1000];
self.databToBeLoaded = data;
[data release];
I provided a couple of updates that I think answer what is going on here. With some test results, my conclusion is that this warning is spurious, meaning it does not really identify improper code. The updates should speak for themselves. They are given above.
I'm trying to switch views in my app using this chunk of code:
self->variable1 = [[NSNumber alloc] initWithInt:0];
self->variable2 = [[NSMutableArray arrayWithCapacity:1];
self->variable3 = [[NSMutableArray arrayWithCapacity:1];
[self presentModalViewController:titleScreen animated:YES];
If I comment out all of the allocated variable lines, the code works fine. If it leave just 1 line in the code crashes with the "EXC_BAD_ACCESS" error. Why is this happening? The variables aren't being used at all, just declared for later use. I'm not getting any compile errors on the lines either. What am I doing wrong?
UPDATE:
Thank you everyone for the help. I change the way I declare my variables to #property/#synth to clean up my code, but it didn't fix the problem. After a long time of fiddling I fixed it. I changed the code from this:
self.variable1 = [[NSNumber alloc] initWithInt:0];
to this:
self.variable1 = [NSNumber alloc];
[self.variable1 initWithInt:0];
and it worked! Can someone explain why this worked and the first line didn't?
Update:
Thank you Peter Hosey for showing me my evil ways. This time I'm pretty sure it's fixed. I was storing my variable Releases in
-(void)release
I didn't realize xCode will release when it needs to. I moved all the variable releases to
-(void)Destroy
so I can release everything on MY command. Now the code works. Thanks again!
I suggest that you declare variable1, variable2, and variable3 as properties, not instance variables. Then, use self.variable1, self.variable2, and self.variable3 to access them.
The dot syntax (self.variable1, etc.) uses the memory management policy you declared on each property; the arrow syntax (self->variable1, etc.) will access the variables directly. The crash is because you created two arrays in away that doesn't leave you owning them, and then did not assign the arrays to a property that would retain them.
You may also want to upgrade your project to use ARC. Then there is no memory-management difference; assigning to the instance variables rather than the properties will not cause the object to be prematurely released, because ARC considers instance variables to be ownerships by default. You may still want to switch to using properties after you switch to ARC, but not to prevent a crash.
In response to your edit:
I change the way I declare my variables to #property/#synth to clean up my code, but it didn't fix the problem.
Then something else was wrong.
You never did say much about the problem itself. You said you got an EXC_BAD_ACCESS, but not what statement triggered the crash or on what grounds you blamed it on the code you showed.
I changed the code from this:
self.variable1 = [[NSNumber alloc] initWithInt:0];
That's the correct code, though. That's what you should be using.
to this:
self.variable1 = [NSNumber alloc];
[self.variable1 initWithInt:0];
Noooo! That code is wrong, wrong, wrong, on multiple levels.
init methods (including initWithWhatever: methods) are not guaranteed to return the same object you sent the message to. NSNumber's initWithInt: very probably doesn't.
That object creates an uninitialized NSNumber object and assigns that to the property. Then it sends initWithInt: to that object, which will return an initialized object, which can be and very probably will be a different object. Now you are holding an uninitialized object (which you will try to use later) and have dropped the initialized object on the floor.
Never, ever, ever send alloc and init(With…) in separate expressions. Always send them in the same expression. No exceptions. Otherwise, you risk holding the uninitialized object rather than the initialized object. In your case (with NSNumbers), that is almost certainly what will happen.
What you should be doing is declaring and synthesizing a strong property that owns the NSNumber object, and creating the NSNumber object in a single statement: either [[NSNumber alloc] initWithInt:] or [NSNumber numberWithInt:]. If you're not using ARC, you'll want the latter, since the property will retain the object. If you are using ARC, they're effectively equivalent.
And if you get a crash with that code, then something else is wrong, so please tell us—either in this question or in a new question—about the crash so we can help you find the true cause of it.
variable2 and variable3 are being autoreleased before you actually access them (presumably) later after presenting the modal view.
At the very least change the lines to:
self->variable2 = [[NSMutableArray arrayWithCapacity:1] retain];
self->variable3 = [[NSMutableArray arrayWithCapacity:1] retain];
or
self->variable2 = [[NSMutableArray alloc] initWithCapacity:1];
self->variable3 = [[NSMutableArray alloc] initWithCapacity:1];
variable1 should be fine.
Best would be to use #property and #synthesize so you can use dot notation:
.h
#interface MyClass : SuperClass
#property (nonatomic,retain) NSMutableArray *variable2;
#property (nonatomic,retain) NSMutableArray *variable3;
#end
.m
#implementation MyClass
#synthesize variable2,varible3;
- (void)foo {
self.variable2 = [NSMutableArray arrayWithCapacity:1];
self.variable3 = [NSMutableArray arrayWithCapacity:1];
}
#end
By default, all instance variables in objective-c have protected scope. So unless you have explicitly declared them public in your interface file as:
#interface MYClass {
#public
NSNumber *variable1;
NSMutableArray *variable2;
NSMutableArray *variable3;
}
//...
#end
then they will not be accessible using the struct dereferencing operator. This is likely the cause of those EXC_BAD_ACCESS errors.
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).