无法从init系列中的方法中分配给self?

Adn*_*han 23 objective-c ios

我使用自己像" 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;
}
Run Code Online (Sandbox Code Playgroud)

错误:

 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:.
Run Code Online (Sandbox Code Playgroud)

Mar*_*bri 61

如果您的方法是初始化程序,则必须以init:

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

否则,您可以将其更改为类方法,并返回一个新实例:

+ (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;
}
Run Code Online (Sandbox Code Playgroud)

  • 此外,如果紧跟在`init`之后的字符未大写,则会得到相同的错误(例如`initwithDropDown:`).我花了很多年才找到那个坏男孩...... (18认同)

Jan*_*ano 6

由于以下约定,您无法selfinit方法外部进行初始化:

如果对象的类没有实现初始化程序,则Objective-C运行时会调用最近的祖先的初始化程序.

并且因为某些方法的名称被运行时的内存管理系统识别:

当方法的名称以alloc init,retain或copy开头时,它意味着它是为调用者创建的,调用者有责任在完成对象时释放该对象.否则返回的方法不归调用者所有,并且他必须表明他希望保持对对象调用retain.

因此,所有初始化程序都应该写成以下变体:

- (id) init {
    self = [super init];
    if (self){
        _someVariable = @"someValue";
    }
    return self;
}
Run Code Online (Sandbox Code Playgroud)
  • 不要使用,if ((self = [super init]))因为它很难看.
  • 不要使用,self.someVariable因为该对象可能尚未初始化.改为使用直接变量访问(_someVariable).
  • 我们写self = [super init],而不仅仅是[super init]因为可能返回不同的实例.
  • 我们写,if (self)因为会有返回的情况nil.

但是,您的方法还有两个问题:

  • 您在同一方法中组合对象创建([super init])和动作(-showDropDown::::).您应该编写两个单独的方法.
  • 您的方法的名称是-showDropDown::::.Objective-C程序员期望自我记录方法名称-showDropDown:height:array:direction:.我猜你来自不同的语言,但是在罗马时,就像罗马人一样,或者你不会和团队的其他成员一起玩.