Memory Management (fun fun fun)

Discussion in 'iOS Programming' started by TwinofSian, Nov 5, 2011.

  1. TwinofSian macrumors member

    Joined:
    Oct 23, 2011
    #1
    Hey guys, I have been doing a tutorial and this is what my code looks like:
    Code:
    #import <Foundation/Foundation.h>
    #import "SimpleCar.h"
    
    int main (int argc, const char* argv[]) {
         NSAutoreleasePool* pool = [NSAutoreleasePool alloc] init];
    
         SimpleCar* myCar = [[SimpleCar alloc] init];
    
        NSNumber* newVin = [NSNumber numberWithInt:123];
        NSNumber* newEnginesz = [NSNumber numberWithFloat: 2.1];
         [myCar setVin:newVin];
         [myCar setEnginesz:newEnginesz];
         [myCar setMake:@"Honda" andModel:@"Civic"];
    
       NSLog(@"The car is %@ %@", [myCar make], [myCar model]);
       NSLog(@"The vin is: %@", [myCar vin]);
       NSLog(@"Engine size: %@". [myCar enginesz]);
    
        [myCar release];
    
        [pool drain];
    
         NSLog(@"retainCount for car %d", [myCar retainCount]);
    
         return 0;
    
    }
    One thing I have been having trouble with is my retainCount keeps saying I have a retainCount of 1, even though the myCar object has been released, followed by a pool drain.
    I even tried putting my NSLog for the Retain Count at the very bottom, right above the return 0; }
    Shouldn’t it be a retainCount of 0?
    write [pool drain]; again just creates a memory leak.

    'preciate any and all help
     
  2. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #2
    The object is dead. You're seeing the last value before it became dead. It's not necessary to set its retain count to 0, because it's dead.

    Do not believe any value in any dead object. Ever.
     
  3. TwinofSian thread starter macrumors member

    Joined:
    Oct 23, 2011
    #3
    awesome, thanks so much for the response. How can you tell it is dead? Is that just the rule for a [object release]; in general?
     
  4. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #4
    You can't really, nor should you. Just follow the rules in the Advanced Memory Management Programming Guide. Alternatively, turn Automatic Retain Counting (ARC) on and forget about retaining and releasing your objects. See the Transitioning to ARC Release Notes.

    If your program is crashing and you think it's because you're accessing dead, zombie objects, you can use the Instruments application to find out. Here's a tutorial.
     
  5. TwinofSian thread starter macrumors member

    Joined:
    Oct 23, 2011
    #5

    Thanks for the links! I am only running this code through the Console, and it doesn't "crash" on me (or give me build errors) but it kept giving me that retainCount number of 1, when according to my code, it should be 0.

    The only time the console reported a memory leak was when I wrote [pool release]; twice.

    That's why I asked.
     
  6. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #6
    You released it. You no longer own it. Therefore, you shouldn't be referencing it at all. For anything.

    If your release caused it to dealloc, then it's dead. If not, such as because someone else still owns it, then it's not dead. Either way, you released it, so you no longer own it, and shouldn't be referencing it.

    If you don't own an object, or the object hasn't been given to you temporarily (e.g. returned by something else), then you can't tell whether it's dead or not. The only way to know if an object is live is by asking it. But if it's dead, it can't respond properly (a consequence of being dead). Or it may sort-of respond semi-properly in certain situations. In general, asking dead objects if they're alive, or alive enough to respond, is futile.

    By "dead" I specifically mean dealloc'ed. If you understand the relationship between release and dealloc, you'll understand the above. If not, you should study them.


    Telling dead objects to do things or respond to message is not a leak. So nothing will report it as a leak.

    A leak is a live object that no one has a reference to. So it just keeps living, and can never die, because no one has a reference to it to tell it to release. It's an immortal space-occupier doing nothing useful. (Immortal until the process it's in terminates.)
     
  7. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #7
    Because you've then over-released the object.
     
  8. TwinofSian, Nov 5, 2011
    Last edited: Nov 5, 2011

    TwinofSian thread starter macrumors member

    Joined:
    Oct 23, 2011
    #8
    While we're on the subject of tutorials, in a different series of the same one, the author is lecturing on categories.

    This is what the ultimate code is supposed to look like. I created a new Xcode project for it.

    stringtest.m (main project)

    Code:
    int main () {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    
    NSString* testString = @"Just a test";
    
    [testString reverseString];
    
    NSLog(@"Reversed: '%@'", testString);
    
    [pool drain];
    
    return 0;
    }
    the header file (NSString+reverse.h)
    Code:
    @interface NSString (reverse)
    
    -(NSString *) reverseString;
    
    @end
    The implement file (NSString+reverse.m)
    Code:
    @implementation NSString (reverse)
    
    -(NSString *)reverseString {
        int length = [self length];
        NSMutableString *reversedString;
    
        reversedString = [[NSMutableString alloc] initWithCapacity: length];
    
        while (length > 0) {
    	    [reversedString appendString:[NSString stringWithFormat:@"%C", [self characterAtIndex:--length]]];
        }
    
        return [reversedString autorelease];
    }
    
    @end
    So the desired result is for the output to be a reversed version of "Just a Test," but what I actually when I fire this up in the console is: "Reversed: "Just a test"

    I believe I have done everything correctly, and I have tried copying+pasting from the original code as well to make sure I am doing it right, but the darn'd thing just isn't working. Any ideas?
     
  9. North Bronson macrumors 6502

    Joined:
    Oct 31, 2007
    Location:
    San José
    #9
    What author gave you this tutorial?

    First of all, always always always prefix your categories with some custom identifier. This protects you if Apple ever decides to implement an identical method in a future version of the OS.

    Code:
    - (NSString *)reverseString;
    becomes:

    Code:
    - (NSString *)NBS_reverseString;
    Second of all, enumerating through characters should be done with the block-based APIs. Trying to enumerate through individual unichars is not totally robust; many unicode characters can be represented as sequences of multiple unichars -- you want to enumerate through every one of these sequences, not necessarily every individual character.
     
  10. jiminaus, Nov 5, 2011
    Last edited: Nov 5, 2011

    jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #10
    This is the faulty line. I'll leave it you to figure out why.

    And I second North Bronson. I'm bilingual in Mandarin Chinese (to the detriment of my native English). Many of the Chinese characters I use don't exist on the Basic Multilingual Plane and are coded with surrogate pairs (sequences of unichars). The reverseString method you've code would break my strings because it would reverse the unichars in a multi-unichar character thereby corrupting it.
     
  11. TwinofSian, Nov 5, 2011
    Last edited: Nov 5, 2011

    TwinofSian thread starter macrumors member

    Joined:
    Oct 23, 2011
    #11
    I got this basic tutorial off of the mobile.tutsplus site. The author was Dan Walker

    I am very new to programming in general, and while I am aware of these terms, I am not 100% sure what you are referring to.

    Specifically unichars I imagine refer to something like "reverseString" correct?

    I am still trying to decipher what you mean when you say "enumerating through characters should be done with the block-based APIs.

    Well, I tried
    Code:
    [testString reverseString:testString];
    in my attempt to make the program apply the method to the object, and while the console did run, it produced a warning, as well as a terminate within the console "due to uncaught exception 'NSInvalidArgumentException.'"
     
  12. North Bronson macrumors 6502

    Joined:
    Oct 31, 2007
    Location:
    San José
    #12
    Mr. Walker claims that his tutorial goes "through not just the bare essentials, but also the best practices you can apply to ensure your code is the best it can be." This is a very irresponsible claim for him to make.

    Stick with Steve Kochan's texts for learning the language. He's the best in the business.
     
  13. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #13
    Blindly trying stuff is going to make a very hard, long, rocky road.

    I don't like Internet tutorials. I would never tell someone to learn from Internet tutorial. You cannot be sure of the quality of the information you're getting, and in my experience they don't actually teach you anything.

    Do you understand the reverseString method? Do you understand how it works and what it does exactly? The answer is not just "it reverses a string".
     
  14. TwinofSian thread starter macrumors member

    Joined:
    Oct 23, 2011
    #14
    jimnaus, yes I understand that the reverseString method is being called and 'applied' to the testString, which is an object of NSString. The syntax is still a little awkward to me, so that's why I tried doing
    Code:
    [testString reverseString:testString]
    but again, it's my first week doing this (I tried fiddling in the past with C, but MS Visual Studios kept giving me trouble, so I dropped it to do other projects, now I am on Xcode on the Mac), so everything can be a little overwhelming.

    This time around, I tried testString = [testString reverseString];

    I admit, I looked at previous examples, to try to figure it out. This is a lot more like Algebra than I realized at first. An object already defined, but you're trying to call a method on it, but you need to define a 'static' example of that object.

    I'm not sure if I am making much sense, but I got the intended result: the console spat out: "Reversed: 'tset a tsuJ'"

    @North Bronson, my next sets of online Tutorials, (which were recommended to me by Nat) come directly from Kochan's book (with his permission).
     
  15. jiminaus, Nov 5, 2011
    Last edited: Nov 5, 2011

    jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #15
    This is the flaw in your thinking. Your calling the reverseString method is applying nothing to the existing NSString object. It's creating a new NSMutableString object, manipulating the characters in that, and then returning it. The original NSString object is untouched.

    That is why [testString reverseString] did nothing. It returned a new object containing the reversed string, but you didn't do anything with it.

    [testString reverseString:testString] didn't work because reverseString is different from reverseString:. The former doesn't take a parameter, the latter does but you didn't define a reverseString: method. The colon is more than just a syntactic separator, it's a part of the method name.


    This is just so wrong. I think you've just been guessing at what your code's been doing. This isn't good enough. A computer won't tolerate guessed code.


    A word of advice from someone who's been before you. Learning the Objective-C language is the easy part of learning to create iOS apps. The more difficult part is learning how to use all the classes in Cocoa Touch. But the most difficult part is learning how to go from what you want to a feasible design, that is how do you orchestrate the Couch Touch classes and your own classes to get implement your requirements.

    But while learning Objective-C is the easiest part. You've got to know it well and be comfortable in it. If you go too fast and don't thoroughly learn this foundation, your house of cards will surely fall.

    Do yourself a favour, stop using random Internet tutorials, and pickup a good book on iOS programming. To find a good book, start with this FAQ the appears at the top of this forum. Then search this forum for theads along the lines of how do I get started or books for beginners. This kind of question is asked here all the time.
     
  16. TwinofSian thread starter macrumors member

    Joined:
    Oct 23, 2011
    #16
    Thank you for the advice, I genuinely appreciate it.
     

Share This Page