Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C: Instance variable used while 'self' not set... but it is

I've been tasked with cleaning up some Clang errors in a code base. I am very new to iPhone development and Objective C, but have found most of the problems trivial... this one is stumping me though, when I'm sure its something embarrassing.

From a ZAttributedString class:

- (id)initWithAttributedString:(ZAttributedString *)attr {
    NSParameterAssert(attr != nil);
    if ((self = [super init])) {
        _buffer = [attr->_buffer mutableCopy];
        _attributes = [[NSMutableArray alloc] initWithArray:attr->_attributes copyItems:YES];
    }
    return self;
}

The clang warning is "Instance variable used while 'self' is not set to the result of '[super or self] init...]', with the dereferencing of attr's _buffer attribute being highlighted.

If it helps, the warning also seems to mention that the problem is found when calling from this method:

- (id)copyWithZone(NSZone *)zone {
    return [(ZAttributedString *)[ZAttributedString allocWithZone:zone] initWithAttributedString:self];
}

Can anyone please explain to me what exactly the defect is here?

TIA!

like image 527
user2608447 Avatar asked Jul 22 '13 21:07

user2608447


People also ask

What is instance variable in Obj C?

An instance variable is a variable that exists and holds its value for the life of the object. The memory used for instance variables is allocated when the object is first created (through alloc), and freed when the object is deallocated.

Is self an instance variable?

The self variable is used to represent the instance of the class which is often used in object-oriented programming. It works as a reference to the object. Python uses the self parameter to refer to instance attributes and methods of the class.

Can we use instance variable outside the class?

What is instance variable in Java? Instance variables in Java are non-static variables which are defined in a class outside any method, constructor or a block.

What is an instance variable and how is it used in this level?

An instance variable is a variable which is declared in a class but outside of constructors, methods, or blocks. Instance variables are created when an object is instantiated, and are accessible to all the constructors, methods, or blocks in the class. Access modifiers can be given to the instance variable.


2 Answers

Do not use -> to access instance variables, especially when the ivar is from some other object.

Do this:

_buffer = [[attr string] mutableCopy];

Same goes for that nasty attr->_attributes. Apparently, ZAttributedStringexposesattributes` as a property in the private header.


That compiler warning does seem, at the very most optimistic, entirely misleading and, likely, quite wrong in description. Filing a bug to have that clarified would be useful.


Note that @maddy's claim that using -> to access the instance variables directly in the attr string passed as it acts like a copy constructor is incorrect.

The incoming attr may be a ZAttributedString instance or an instance of a subclass or, really, an instance of any class that implements the same interface as ZAttributedString. Thus, you really must go through the accessors to guarantee that you are grabbing the correct state.

Now, as an implementation detail, ZAttributedString could require that the inbound instance be a non-subclassed instance of ZAttributedString, but it should use isMemberOfClass: to assert that requirement (and, please, don't do that).

The only spot where direct ivar access is sometimes used to pull state from another object is in the implementation of copyWithZone:, but that is exceedingly fragile and oft leads to whacky broken behavior. In fact, copyWithZone: (outside of the various plist compatible value classes) has been rife with fragility and the source of many many many bugs.

like image 65
bbum Avatar answered Oct 01 '22 18:10

bbum


It seems like you are seeing the exact same bug as this: "[Bug 15092] New: static analyzer false positive: reports instance variable used while 'self' is not set to the result of [(super or self)] init". It has a very similar code attached to reproduce the bug.

If you run that code in Xcode 4.6.3 you can verify that it gives the same false warning as you are seeing.

enter image description here

The bug was resolved with the comment:

This is fixed in trunk, or at least mostly fixed -- there are still a few edge cases where the warning will fire, but not your project.

(Dave, for now all of the main analyzer engineers do work at Apple, so there's no real need to file duplicates. The LLVM people who don't work at Apple don't have access to Apple Clang, which ships with Xcode, and this fix didn't make Xcode 4.6. You can also get newer checker builds from http://clang-analyzer.llvm.org)

As you can see the bug is fixed but still present in Xcode 4.6. Hold out for the next version of Xcode and the analyzer warning should be gone.

like image 37
David Rönnqvist Avatar answered Oct 01 '22 18:10

David Rönnqvist