No, foo
is variable holding a pointer to an NSString
. The assignment foo = @"bar"
sets the value stored by the pointer foo
to the address of the NSString @"bar"
. There is no copy made. If foo
already pointed to an other NSString
instance that was not a string constsant (i.e. like @"bar"
) and there are no other references to that instance, then you have a memory leak. You would
[foo release];
foo = @"bar";
in that case. You do not need to retain or release string constants like @"bar"
.
String constants cannot be mutated, so you will get a runtime error if you try to modify the value of a constant string. There's no difference between assigning @"bar"
to an NSString*
vs an NSMutableString*
. Of course, you won't be able to use the mutating methods of the NSMutableString
without a runtime error just because you assign the address of @"bar" (an NSString instance) to a variable of type NSMutableString*
. If you want to mutate the string, you would do
NSMutableString *mutableFoo = [@"bar" mutableCopy];
In this case, a copy is obviously made and you are responsible for releasing mutableFoo
when you're done with it.
Since I am using a background image, none of these solutions worked well for me. Here is a solution that does some fun objective-c magic and offers a drop in solution with minimal code.
First, add a category to UIButton
that overrides the hit test and also adds a property for expanding the hit test frame.
UIButton+Extensions.h
@interface UIButton (Extensions)
@property(nonatomic, assign) UIEdgeInsets hitTestEdgeInsets;
@end
UIButton+Extensions.m
#import "UIButton+Extensions.h"
#import <objc/runtime.h>
@implementation UIButton (Extensions)
@dynamic hitTestEdgeInsets;
static const NSString *KEY_HIT_TEST_EDGE_INSETS = @"HitTestEdgeInsets";
-(void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets {
NSValue *value = [NSValue value:&hitTestEdgeInsets withObjCType:@encode(UIEdgeInsets)];
objc_setAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(UIEdgeInsets)hitTestEdgeInsets {
NSValue *value = objc_getAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS);
if(value) {
UIEdgeInsets edgeInsets; [value getValue:&edgeInsets]; return edgeInsets;
}else {
return UIEdgeInsetsZero;
}
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || !self.enabled || self.hidden) {
return [super pointInside:point withEvent:event];
}
CGRect relativeFrame = self.bounds;
CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets);
return CGRectContainsPoint(hitFrame, point);
}
@end
Once this class is added, all you need to do is set the edge insets of your button. Note that I chose to add the insets so if you want to make the hit area larger, you must use negative numbers.
[button setHitTestEdgeInsets:UIEdgeInsetsMake(-10, -10, -10, -10)];
Note: Remember to import the category (#import "UIButton+Extensions.h"
) in your classes.
Best Answer
The problem with appending to a string is that unless the string has preallocated all the space required, you're going to need to do some allocations and copying, leading to O(n^2) performance.
A more performant way is to build an NSArray of your list of strings using NSArray:componentsJoinedByString:. Appending to the array is constant time, and since it knows the length of the resulting string before hand, it can provide you the final string in O(n) time.