I have the following method in a NSDictionary category, to do a deep copy, which works fine.
I just upgraded from Xcode 4.1 to 4.2, and the Analyze function gives two analyzer warnings for this code, as indicated:
- (id)deepCopy;
{
id dict = [[NSMutableDictionary alloc] init];
id copy;
for (id key in self)
{
id object = [self objectForKey:key];
if ([object respondsToSelector:#selector(deepCopy)])
copy = [object deepCopy];
else
copy = [object copy];
[dict setObject:copy forKey:key];
// Both -deepCopy and -copy retain the object, and so does -setObject:forKey:, so need to -release:
[copy release]; // Xcode 4.2's Analyze says this is an incorrect decrement of the reference count?!
}
return dict; // Xcode 4.2's Analyze says this is a potential leak
}
Are these bugs in Xcode's analyzer, or are there changes I can make to avoid these warnings?
I'm not using ARC yet, though I am interested if there are additional changes needed to support ARC for this method.
Presumably, it is because deepCopy does not begin with the prefix copy.
So you may want to change to something like copyWithDeepCopiedValues (or something like that), and then see if the analyzer flags that.
Update
As Alexsander noted, you can use attributes to denote reference counting intent. This should (IMO) be the exception to the rule, and used rarely, if ever. Personally, I will not use attributes for objc methods because it is fragile.
The only attribute I have used so far has been consume, and every time I use these attributes has been in statically typed contexts (e.g. C functions and C++ functions and methods).
The reasons you should avoid attributes when possible:
1) Stick with conventions for the programmers' sake. The code is clearer and you do not need to refer to the documentation.
2) The approach is fragile. You can still introduce reference count imbalances, and attributes can be used to introduce build errors due to conflicts in attributes.
The following cases are all built with ARC enabled:
Case #1
#import <Foundation/Foundation.h>
#interface MONType : NSObject
- (NSString *)string __attribute__((objc_method_family(copy)));
#end
#implementation MONType
- (NSString *)string
{
NSMutableString * ret = [NSMutableString new];
[ret appendString:#"MONType"];
return ret;
}
#end
int main (int argc, const char * argv[])
{
#autoreleasepool {
id obj = nil;
if (random() % 2U) {
obj = [[NSAttributedString alloc] initWithString:#"NSAttributedString"];
}
else {
obj = [MONType new];
}
NSLog(#"Result: %#, %#", obj, [obj string]);
}
/* this tool's name is ARC, dump the leaks: */
system("leaks ARC");
return 0;
}
This program produces the following error: error: multiple methods named 'string' found with mismatched result, parameter type or attributes.
Great, the compiler's doing what it can to prevent these issues. What that means is that conflicts in attributes can introduce errors based on the translation. This is bad because when nontrivial codebases are combined and attributes conflict, you will have errors to correct and programs to update. This also means that simply including other libraries in translation units can break existing programs when attributes are used.
Case #2
Header.h
extern id NewObject(void);
Header.m
#import <Foundation/Foundation.h>
#import "Header.h"
#interface MONType : NSObject
- (NSString *)string __attribute__((objc_method_family(copy)));
#end
#implementation MONType
- (NSString *)string
{
NSMutableString * ret = [NSMutableString new];
[ret appendString:#"-[MONType string]"];
return ret;
}
#end
id NewObject(void) {
id obj = nil;
if (random() % 2U) {
obj = [[NSAttributedString alloc] initWithString:#"NSAttributedString"];
}
else {
obj = [MONType new];
}
return obj;
}
main.m
#import <Foundation/Foundation.h>
#import "Header.h"
int main (int argc, const char * argv[])
{
#autoreleasepool {
for (size_t idx = 0; idx < 8; ++idx) {
id obj = NewObject();
NSLog(#"Result: %#, %#", obj, [obj string]);
}
}
/* this tool's name is ARC, dump the leaks: */
system("leaks ARC");
return 0;
}
Ok. This is just bad. We've introduced leaks because the necessary information was not available in the translation unit. Here's the leaks report:
leaks Report Version: 2.0
Process 7778: 1230 nodes malloced for 210 KB
Process 7778: 4 leaks for 192 total leaked bytes.
Leak: 0x1005001f0 size=64 zone: DefaultMallocZone_0x100003000 __NSCFString ObjC CoreFoundation mutable non-inline: "-[MONType string]"
Leak: 0x100500320 size=64 zone: DefaultMallocZone_0x100003000 __NSCFString ObjC CoreFoundation mutable non-inline: "-[MONType string]"
Leak: 0x100500230 size=32 zone: DefaultMallocZone_0x100003000 has-length-byte: "-[MONType string]"
Leak: 0x100500390 size=32 zone: DefaultMallocZone_0x100003000 has-length-byte: "-[MONType string]"
note: the count may differ because we used random()
This means that because MONType is not visible to main(), the compiler bound the ARC properties to methods which were visible to the current TU (that is, string from declarations in Foundation, all of which follow convention). As a result, the compiler got it wrong and we were able to introduce leaks into our program.
Case 3
Using a similar approach, I was also able to introduce negative reference count imbalances (premature releases, or a messaged zombie).
note: Code not provided because Case #2 already illustrates how one can accomplish a reference count imbalance.
Conclusion
You can avoid all these problems and improve readability and maintainability by sticking with convention, rather than using attributes.
Bringing the conversation back to non-ARC code: Using attributes makes manual memory management more difficult for programmers' readability, and for the tools which are there to help you (e.g. compiler, static analysis). If the program is suitably complex such that the tools can't detect such errors, then you should reconsider your design, because it will be equally complex for you or somebody else to debug these issues.
Adding onto #Justin's answer, you can tell the compiler that -deepCopy returns a retained object by appending the NS_RETURNS_RETAINED attribute to the method's declaration like so:
- (id) deepCopy NS_RETURNED_RETAINED;
Alternatively, you can use explicitly control the method's "family" using the objc_method_family attribute like so:
- (id) deepCopy __attribute__((objc_method_family(copy)));
If you do this, the compiler will know that this method is in the copy family and returns a copied value.
Related
When using Swift, the Cocoa frameworks are declared to return native Swift types, even though the frameworks are actually returning Objective-C objects. Likewise, the methods takes Swift types as parameters, where that makes sense.
Suppose I want to call a Cocoa method that (in Objective-C) would give me an NSArray and then pass that to a Cocoa method that takes an NSArray. With code like this:
let a: [AnyObject] = [] // Imagine calling a method that returns a huge NSArray.
let mutable = NSMutableArray()
mutable.addObjectsFromArray(a)
It looks like the huge NSArray is going to get bridged to a Swift array when assigned to a and then bridged back to an NSArray when passed as a parameter. At least that's how it seems from profiling and looking at the disassembly.
Is there a way to avoid these potentially slow conversions when I don't need to actually work with the array in Swift? When I'm just receiving it from Cocoa and then passing it back to Cocoa?
At first, I thought that it would help to add type information for a:
let a: NSArray = [] // Imagine calling a method that returns a huge NSArray.
let mutable = NSMutableArray()
mutable.addObjectsFromArray(a as [AnyObject])
But then I have to convert the parameter to a Swift array later or the compiler will complain.
Furthermore, the disassembly for code like:
let c: NSArray = mutable.subarrayWithRange(NSMakeRange(0, 50))
shows calls to __TF10Foundation22_convertNSArrayToArrayurFGSqCSo7NSArray_GSaq__ and __TFer10FoundationSa19_bridgeToObjectiveCurfGSaq__FT_CSo7NSArray, seemingly converting the return value to Swift and then back to Objective-C. (This happens even with Release builds.) I had hoped that by typing c as NSArray there would be no bridging necessary.
I'm concerned that this could lead to inefficiencies with very large data structures, with many disparate conversions of regular ones, and with collections that are lazy/proxied because they are not necessarily large but may be expensive to compute. It would be nice to be able to receive such an array from Objective-C code and pass it back without having to realize all of the elements of the array if they are never accessed from Swift.
This is a very different performance model than with Core Foundation/Foundation where the bridging was toll-free. There are so many cases where code passes objects back and forth assuming that it will be O(1), and if these are invisibly changed to O(n) the outer algorithms could become quadratic or worse. It's not clear to me what one is supposed to do in this case. If there is no way to turn off the bridging, it seems like everything that touches those objects would need to be rewritten in Objective-C.
Here is some sample timing code based on the above example:
NSArray *getArray() {
static NSMutableArray *result;
if (!result) {
NSMutableArray *array = [NSMutableArray array];
for (NSUInteger i = 0; i < 1000000; i++) {
[array addObjectsFromArray:#[#1, #2, #3, #"foo", #"bar", #"baz"]];
}
result = array;
}
return result;
}
#interface ObjCTests : XCTestCase
#end
#implementation ObjCTests
- (void)testObjC { // 0.27 seconds
[self measureBlock:^{
NSArray *a = getArray();
NSMutableArray *m = [NSMutableArray array];
[m addObjectsFromArray:a];
}];
}
#end
class SwiftTests: XCTestCase {
func testSwift() { // 0.33 seconds
self.measureBlock() {
let a: NSArray = getArray() as NSArray
let m = NSMutableArray()
m.addObjectsFromArray(a as [AnyObject])
}
}
func testSwiftPure() { // 0.83 seconds
self.measureBlock() {
let a = getArray()
var m = [AnyObject]()
m.appendContentsOf(a)
}
}
}
In this example, testSwift() is about 22% slower than testObjC(). Just for fun, I tried doing the array append with the native Swift array, and this was much slower.
A related issue is that when Objective-C code passes Swift code an NSMutableString, the Swift String ends up with a copy of the mutable string. This is good in the sense that it won’t be unexpectedly mutated behind Swift’s back. But if all you need to do is pass a string to Swift and look at it briefly, this copy could add unexpected overhead.
have you tried making an extension?
extension NSMutableArray
{
func addObjectsFromNSArray(array:NSArray)
{
for item in array
{
self.addObject(item);
}
}
}
Now that I had time to actually play with this instead of talking in theory, I am going to revise my answer
Create an extension, but instead, do it in an objective c file
#interface NSMutableArray(Extension)
- (void)addObjectsFromNSArray:(NSObject*) array;
#end
#implementation NSMutableArray(Extension)
- (void)addObjectsFromNSArray:(NSObject*) array
{
[self addObjectsFromArray:(NSArray*)array];
}
#end
I found the code to work a lot faster doing it this way. (Almost 2x from my tests)
testSwift 4.06 seconds
testSwiftPure 7.97 seconds
testSwiftExtension 2.30 seconds
I ran 'analyze" in xcode on a current iOS project to try to track down a freeze issue and there are a number of memory alerts that I don't understand (screenshot of one below).
What is going on there: I have a custom ObjC class extending NSObject; in the init method I alloc/init an NSMutableArray and then in a loop, populate it with NSMutableArrays. This nested array is declared as a property and released in dealloc(). It lives for the life of the app.
Am I doing this wrong? I don't understand the alert#3: # object not referenced in this execution path and has a retain count of +1.
Since my class allocs the outer array, it owns it and will clean it up. Do the inner arrays need to be released?
Thanks for any tips - still new at this.
EDIT/ADDITION
Trying to stamp out the additional memory warnings I am getting so I thought I would add to the question here in the event someone stumbles upon this w/ the same issue.
I am getting the following alert with the code below (the 2nd line "[keyArray addObject: etc"). What is going on: I have a custom class (Key - based on NSObject) that I instance and store in an array. Based on answers to my previous question, I guess my alloc increases the retain count and then when it is added to the array, the retain count isn't decremented - so the memory warning occurs.
What is the proper way to handle something like this? Use a placeholder like this:
Key * k = [[Key alloc] initKeyWithPath:path isBlackKey:NO]];
[keyArray addObject: k];
[k release];
Is that the proper way to do it? Or is there I way to write the custom class to return an autoreleased obj? (thanks and sorry to be so long winded!).
Potential leak of an object allocated on line 460
Method returns an Objective-C object with a +1 retain count (owning reference)
Object allocated on line 460 is not referenced later in this execution path and has a retain count of +1 (object leaked)
-(void) addOctaveToArraysWithTransform:(CGAffineTransform*)trans andPath: (CGMutablePathRef) path
{
path = [self createCF_keyUsingTransform: trans];
[keyArray addObject:[[Key alloc] initKeyWithPath:path isBlackKey:NO]];
}
Key.h
#import <Foundation/Foundation.h>
#import "Key.h"
#interface Key : NSObject {
#public
CGMutablePathRef keyPath;
BOOL isBlackKey;
NSValue * path;
int keyState;
BOOL needsRedraw;
}
#property (nonatomic, assign) int keyState;
#property (nonatomic, assign) BOOL needsRedraw;
#property (nonatomic) CGMutablePathRef keyPath;
-(id) initKeyWithPath:(CGMutablePathRef) aPath isBlackKey:(BOOL)flag;
-(CGMutablePathRef) getKeyPath;
#end
Key.m
#import "Key.h"
#implementation Key
#synthesize keyState, needsRedraw, keyPath;
-(id) initKeyWithPath:(CGMutablePathRef) aPath isBlackKey:(BOOL)flag
{
if ((self = [super init])){
isBlackKey = flag;
keyState = 0;
needsRedraw = NO;
keyPath = aPath;
CGPathRetain(keyPath);
}
return self;
}
-(CGMutablePathRef) getKeyPath
{
return keyPath;
}
#end
Yes, you have to release the inner arrays to balance the alloc/init. Remember the outer array will retain each inner array, and the outer array will presumably release those later. But here you are still responsible for the alloc/init you just did.
Hope that helps.
You have an allocation of an NSMutableArray on each iteration of the for-loop. Instead use: NSMutableArray array] which is a convenience method that return an autoreleased NSMUtableArray suitable for adding to fieldNotes which will retain the NSMutableArray.
I often use Transformable for Core Data attributes, so I can change them later.
However, it seems like, if I want to use NSPredicate to find a NSManagedObject, using "uniqueKey == %#", or "uniqueKey MATCHES[cd] %#", it's not working as it should.
It always misses matching objects, until I change the attributes of the uniqueKey of the matching object to have specific class like NSString, or NSNumber.
Can someone explain the limitation of using NSPredicate with Transformable attributes?
Note: I'm not sure when/if this has changed since 5/2011 (from Scott Ahten's accepted answer), but you can absolutely search with NSPredicate on transformable attributes. Scott correctly explained why your assumptions were broken, but if Can someone explain the limitation of using NSPredicate with Transformable attributes? was your question, he implied that it is not possible, and that is incorrect.
Since the is the first google hit for "Core Data transformable value search nspredicate" (what I searched for trying to find inspiration), I wanted to add my working answer.
How to use NSPredicate with transformable properties
Short, heady answer: you need to be smart about your data transformers. You need to transfrom the value to NSData that contains what I'll call "primitive identifying information", i.e. the smallest, most identifying set of bytes that can be used to reconstruct your object. Long answer, ...
Foremost, consider:
Did you actual mean to use a transformable attribute? If any supported data type -- even binary data -- will suffice, use it.
Do you understand what transformable attributes actually are? How they pack and unpack data to and from the store? Review Non-Standard Persistent Attributes in Apple's documentation.
After reading the above, ask: does custom code that hides a supported type "backing attribute" work for you? Possibly use that technique.
Now, past those considerations, transformable attributes are rather slick. Frankly, writing an NSValueTransformer "FooToData" for Foo instances to NSData seemed cleaner than writing a lot of adhoc custom code. I haven't found a case where Core Data doesn't know it needs to transform the data using the registered NSValueTransformer.
To proceed simply address these concerns:
Did you tell Core Data what transformer to use? Open the Core Data model in table view, click the entity, click the attribute, load the Data Model Inspector pane. Under "Attribute Type: Transformable", set "Name" to your transformer.
Use a default transformer (again, see the previous Apple docs) or write your own transformer -- transformedValue: must return NSData.
NSKeyedUnarchiveFromDataTransformerName is the default transformer and may not suffice, or may draw in somewhat-transient instance data that can make two similar objects be different when they are equal.
The transformed value should contain only -- what I'll call -- "primitive identifying information". The store is going to be comparing bytes, so every byte counts.
You may also register your transformer globally. I have to do this since I actually reuse them elsewhere in the app -- e.g. NSString *name = #"FooTrans"; [NSValueTransformer setValueTransformer:[NSClassFromString(name) new] forName:name];
You probably don't want to use transforms heavily queried data operations - e.g. a large import where the primary key information uses transformers - yikes!
And then in the end, I simply use this to test for equality for high-level object attributes on models with NSPredicates -- e.g. "%K == %#" -- and it works fine. I haven't tried some of the various matching terms, but I wouldn't be surprised if they worked sometimes, and others not.
Here's an example of an NSURL to NSData transformer. Why not just store the string? Yeah, that's fine -- that's a good example of custom code masking the stored attribute. This example illustrates that an extra byte is added to the stringified URL to record if it was a file URL or not -- allowing us to know what constructors to use when the object is unpacked.
// URLToDataTransformer.h - interface
extern NSString *const kURLToDataTransformerName;
#interface URLToDataTransformer : NSValueTransformer
#end
...
// URLToDataTransformer.m - implementation
#import "URLToDataTransformer.h"
NSString *const kURLToDataTransformerName = #"URLToDataTransformer";
#implementation URLToDataTransformer
+ (Class)transformedValueClass { return [NSData class]; }
+ (BOOL)allowsReverseTransformation { return YES; }
- (id)transformedValue:(id)value
{
if (![value isKindOfClass:[NSURL class]])
{
// Log error ...
return nil;
}
NSMutableData *data;
char fileType = 0;
if ([value isFileURL])
{
fileType = 1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value path] dataUsingEncoding:NSUTF8StringEncoding]];
}
else
{
fileType = -1;
data = [NSMutableData dataWithBytes:&fileType length:1];
[data appendData:[[(NSURL *)value absoluteString] dataUsingEncoding:NSUTF8StringEncoding]];
}
return data;
}
- (id)reverseTransformedValue:(id)value
{
if (![value isKindOfClass:[NSData class]])
{
// Log error ...
return nil;
}
NSURL *url = nil;
NSData *data = (NSData *)value;
char fileType = 0;
NSRange range = NSMakeRange(1, [data length]-1);
[data getBytes:&fileType length:1];
if (1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL fileURLWithPath:str];
}
else if (-1 == fileType)
{
NSData *actualData = [data subdataWithRange:range];
NSString *str = [[NSString alloc] initWithData:actualData encoding:NSUTF8StringEncoding];
url = [NSURL URLWithString:str];
}
else
{
// Log error ...
return nil;
}
return url;
}
#end
Transformable attributes are usually persisted as archived binary data. As such, you are attempting to compare an instance of NSData with an instance of NSString or NSNumber.
Since these classes interpret the same data in different ways, they are not considered a match.
you can try this way
NSExpression *exprPath = [NSExpression expressionForKeyPath:#"transformable_field"];
NSExpression *exprKeyword = [NSExpression expressionForConstantValue:nsdataValue];
NSPredicate *predicate = [NSComparisonPredicate predicateWithLeftExpression:exprPath rightExpression:exprKeyword modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType options:0];
For some reason I thought this was valid under the memory management naming rules:
Bar *bar = [Bar new];
[Foo fooWithNewBar:bar];
// no need to release bar, foo took ownership
However now I'm running my static analysis, it thinks there's a potential leak everytime I did this.
I see there is __attribute((ns_consumed)) which I could use on the fooWithNewBar declaration. But Xcode 4.0.1's Clang does not yet support this attribute.
So, there's no such naming pattern?
I also think there’s no naming pattern corresponding to ns_consumed in your case. Naming patterns are largely driven by NeXTSTEP/Apple and I can’t think of a method in Apple’s frameworks with the same semantics you want.
Note, however, that you can tell Xcode to use a more recent version of Clang Static Analyser that supports the ns_consumed attribute, which was released with checker-254.
I’m using checker-256 (released today, but any version >= 254 should work) and I’ve just tried the following:
// MyClass.h
#ifndef __has_feature // Optional.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#ifndef NS_CONSUMED
#if __has_feature(attribute_ns_consumed)
#define NS_CONSUMED __attribute__((ns_consumed))
#else
#define NS_CONSUMED
#endif
#endif
#interface MyClass : NSObject {
#private
NSString *_string;
}
+ (MyClass *)myClassWithNewStringConsumed:(NSString *) NS_CONSUMED string NS_RETURNS_RETAINED;
+ (MyClass *)myClassWithNewString:(NSString *)string NS_RETURNS_RETAINED;
#end
and
// MyClass.m
#import "MyClass.h"
#implementation MyClass
+ (MyClass *)myClassWithNewStringConsumed:(NSString *)string {
MyClass *o = [MyClass new];
if (o) o->_string = string;
return o;
}
+ (MyClass *)myClassWithNewString:(NSString *)string {
MyClass *o = [MyClass new];
if (o) o->_string = string;
return o;
}
#end
This code gives a static analyser warning for a potential leak of the string stored in s:
// SomewhereElse.m
NSString *s = [[NSString alloc] initWithFormat:#"%d",
[[NSProcessInfo processInfo] processIdentifier]];
MyClass *o = [MyClass myClassWithNewString:s];
[o release];
whereas this code, which uses the method parameter with an ns_consumed attribute, doesn’t give a static analyser warning:
// SomewhereElse.m
NSString *s = [[NSString alloc] initWithFormat:#"%d",
[[NSProcessInfo processInfo] processIdentifier]];
MyClass *o = [MyClass myClassWithNewStringConsumed:s];
[o release];
There is no such pattern. Wherever I think I read about it, I didn't.
Bar *bar = [Bar new];
You own bar.
[Foo fooWithNewBar:bar];
If this wants to own bar, it should be retaining it. That doesn't relinquish your ownership, so you still have to release bar.
I've never seen the pattern you're using.
Foo took an interest in Bar, but *bar still has interest until [bar release] that interest.
Ownership in Objective-C reference-counted memory management is C++ share_ptr, rather than auto_ptr style. In other words, you don't transfer ownership to the Foo instance. Rather the Foo instance declares a share of ownerhsip in your Bar instance (leaving you, the caller of [Bar new] with a share of ownership as well). You always need to relinquish your ownership share of an instance before it may be deallocated. Thus, your example should be
Bar *bar = [[Bar alloc] init]; //Most Obj-C devs prefer alloc/init. When in Rome...
[Foo fooWithNewBar:[bar autorelease]]; //relinquish ownership of bar
Note that you have to use -autorelease rather than -release to relinquish your ownership share because Foo needs a chance to claim an ownership stake before bar is deallocated.
I'm Delphi programmer and very new to Cocoa.
at first I tried this :
-(void)awakeFromNib
{
int i;
NSString *mystr;
for (i=1;i<=24;i++)
{
[comboHour addItemWithObjectValue:i];
}
}
But it didn't work. Then I tried to search on Google but no luck.
After experimenting about 30 min, I come with this:
-(void)awakeFromNib
{
int i;
NSString *mystr;
for (i=1;i<=24;i++)
{
mystr = [[NSString alloc]initWithFormat:#"%d",i];
[comboHour addItemWithObjectValue:mystr];
//[mystr dealloc];
}
}
My questions are:
Is this the right way to do that ?
Do I always need to alloc new
NSString to change its value from
integer ?
When I uncomment [mystr dealloc],
why it won't run ?
Does it cause memory leak to alloc
without dealloc ?
Where can I find basic tutorial like
this on internet ?
Thanks in advance
Do I always need to alloc new NSString to change its value from integer ?
Generally yes; however, there are more convenient ways to create strings (and many other types of objects) than using alloc and init (see autorelease pools below)
You can pass any Objective-C object type to addItemWithObjectValue:, including NSString and NSNumber objects. Both classes have a number of convenient class methods you can use to create new instances, for example:
for (int i = 0; i < 24; ++i)
{
[comboHour addItemWithObjectValue:[NSNumber numberWithInt:i]];
}
When I uncomment [mystr dealloc], why it won't run ?
Never call dealloc. Use release instead.
Cocoa objects are reference counted, like COM objects in Delphi. Like COM, you call release when you're finished with an object. When an object has no more references it is automatically deallocated.
Unlike COM, Cocoa has "autorelease pools", which allows you to, for example, create a new NSString instance without having to worry about calling release on it.
For example: [NSString stringWithFormat:#"%d", 123] creates an "autoreleased" string instance. You don't have to release it when you're done. This is true of all methods that return an object, except new and init methods.
Does it cause memory leak to alloc without dealloc ?
Yes, unless you're using garbage collection.
Where can I find basic tutorial like this on internet ?
See Practical Memory Management
The correct way is:
-(void)awakeFromNib
{
int i;
for (i=1;i<=24;i++)
{
NSString *mystr = [[NSString alloc]initWithFormat:#"%d",i];
[comboHour addItemWithObjectValue:mystr];
[mystr release];
}
}
You can use NSNumber instead of NSString, which might be preferable depending on your context.
You do need to create a new object everytime, because addItemWithObjectValue: is expecting an object rather than a primitive.
You can create a new object (e.g. `NSString), via two methods:
Using alloc/init, like how you did it initially. Such initializations require the release of the object once it isn't required anymore in the allocation scope, using release rather than dealloc.
Using stringWithFormat: factory methods that use auto release pool to release themselves "automatically". The code would look like:
-(void)awakeFromNib
{
int i;
for (i=1; i <= 24; i++) {
NSString *s = [NSString stringWithFormat:#"%d", i];
[comboHour addItemWithObjectValue:s];
}
}
However, it is recommended not to use such construction within loops.
For memory issues, check out the Memory Management Programming Guide for Cocoa
Based on the code you posted and your stated experience level, I recommend going through Apple's Currency Converter tutorial if you haven't already. It's the standard Cocoa tutorial every beginner should read. Fundamentals like interacting with IBOutlets are covered.