24

我正在使用 self like " self = [super init];",下面的代码给我一个错误 " cannot assign to self out of a method in the init family"

- (id)showDropDown:(UIButton *)b:(CGFloat *)height:(NSArray *)arr:(NSString *)direction {
    btnSender = b;
    animationDirection = direction;
    self = [super init];
    if (self) {
        // Initialization code
        CGRect btn = b.frame;
        self.list = [NSArray arrayWithArray:arr];

        if ([direction isEqualToString:@"up"]) {
            self.frame = CGRectMake(btn.origin.x, btn.origin.y, btn.size.width, 0);
            self.layer.shadowOffset = CGSizeMake(-5, -5);
        }else if ([direction isEqualToString:@"down"]) {
            self.frame = CGRectMake(btn.origin.x, btn.origin.y+btn.size.height, btn.size.width, 0);
            self.layer.shadowOffset = CGSizeMake(-5, 5);
        }

        self.layer.masksToBounds = NO;
        self.layer.cornerRadius = 8;
        self.layer.shadowRadius = 5;
        self.layer.shadowOpacity = 0.5;

        table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, btn.size.width, 0)];
        table.delegate = self;
        table.dataSource = self;
        table.layer.cornerRadius = 5;
        table.backgroundColor = [UIColor colorWithRed:0.239 green:0.239 blue:0.239 alpha:1];
        table.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
        table.separatorColor = [UIColor grayColor];

        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:0.5];
        if ([direction isEqualToString:@"up"]) {
            self.frame = CGRectMake(btn.origin.x, btn.origin.y-*height, btn.size.width, *height);
        } else if([direction isEqualToString:@"down"]) {
            self.frame = CGRectMake(btn.origin.x, btn.origin.y+btn.size.height, btn.size.width, *height);
        }
        table.frame = CGRectMake(0, 0, btn.size.width, *height);
        [UIView commitAnimations];

        [b.superview addSubview:self];
        [self addSubview:table];
    }
    return self;
}

错误:

 Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Requesting the window of a view (<NIDropDown: 0x684ac50; frame = (0 0; 0 0); transform = [0, 0, 0, 0, 0, 0]; alpha = 0; opaque = NO; layer = (null)>) with a nil layer. This view probably hasn't received initWithFrame: or initWithCoder:.
4

5 回答 5

64

If your method is an initializer, it must start with init:

- (instancetype)initWithDropDown:(UIButton *)b:(CGFloat *)height:(NSArray *)arr:(NSString *)direction

Otherwise, you can change it to be a class method, and return a new instance:

+ (instancetype)showDropDown:(UIButton *)b:(CGFloat *)height:(NSArray *)arr:(NSString *)direction
{
    btnSender = b;
    animationDirection = direction;
    YourClassName obj = [[self alloc] init];
    if (obj) {
        // Initialization code
        // …
    }
    return obj;
}
于 2013-04-15T10:56:13.100 回答
7

You can't initialize self outside an init method because of the following convention:

If an object’s class does not implement an initializer, the Objective-C runtime invokes the initializer of the nearest ancestor instead.

and because the name of some methods is recognized by the memory management system of the runtime:

When the name of a method starts with alloc init, retain, or copy, it means it's being created for the caller, who has the responsibility to release the object when he is done with it. Otherwise the method returned is not owned by the caller, and he has to indicate he wants to keep it calling retain on the object.

Therefore, all initializers should be written as a variation of this:

- (id) init {
    self = [super init];
    if (self){
        _someVariable = @"someValue";
    }
    return self;
}
  • Don't use if ((self = [super init])) because it's ugly.
  • Don't use self.someVariable because the object may not be initialized yet. Use direct variable access instead (_someVariable).
  • We write self = [super init] and not just [super init] because a different instance may be returned.
  • We write if (self) because there will be cases where it will return nil.

However, there are two more problems with your method:

  • You are combining object creation ([super init]) and an action (-showDropDown::::) in the same method. You should write two separate methods instead.
  • The name of your method is -showDropDown::::. Objective-C programmers expect self documenting method names like -showDropDown:height:array:direction: instead. I guess you come from a different language, but when in Rome, do as Romans do, or else you won't be playing along with the rest of the team.
于 2013-04-15T11:21:04.043 回答
3

Check your spelling in this method

-(id)initwithArray:(NSArray *)array  

Code: (Objective-C)

-(id)initWithArray:(NSArray *)array  
于 2017-03-22T06:57:28.287 回答
1
于 2013-04-15T10:55:03.683 回答
0

Just in case if someone made mistake similar to me, It might be helpful. Please change -(void) to -(id). You need to make sure that you are returning an id.If you use -(void) for both declaration and definition of initialiser, compiler will give you same error as mentioned in question, without telling you to change return type.

于 2019-11-25T12:30:38.337 回答