284

When converting a project to use ARC what does "switch case is in protected scope" mean? I am converting a project to use ARC, using Xcode 4 Edit -> Refactor -> Convert to Objective-C ARC... One of the errors I get is "switch case is in protected scope" on "some" of the switches in a switch case.

Edit, Here is the code:

the ERROR is marked on the "default" case:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"";
    UITableViewCell *cell ;
    switch (tableView.tag) {
        case 1:
            CellIdentifier = @"CellAuthor";
            cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
            if (cell == nil) {
                cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        }
        cell.textLabel.text = [[prefQueries objectAtIndex:[indexPath row]] valueForKey:@"queryString"];
        break;
    case 2:
        CellIdentifier = @"CellJournal";
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        }
        cell.textLabel.text = [[prefJournals objectAtIndex:[indexPath row]] valueForKey:@"name"];

        NSData * icon = [[prefJournals objectAtIndex:[indexPath row]] valueForKey:@"icon"];
        if (!icon) {
            icon = UIImagePNGRepresentation([UIImage imageNamed:@"blank72"]);
        }
        cell.imageView.image = [UIImage imageWithData:icon];

        break;

    default:
        CellIdentifier = @"Cell";
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
            }
        break;
    }


    return cell;
}
Kazuki Sakamoto
  • 13,929
  • 2
  • 34
  • 96
Ali
  • 18,665
  • 21
  • 103
  • 138

8 Answers8

651

Surround each case itself with braces {}. That should fix the issue (it did for me in one of my projects).

FeifanZ
  • 16,250
  • 7
  • 45
  • 84
  • 12
    The braces help the compiler understand scope. I know GCC used to issue a warning if you declared a new variable at the first line of a case statement without the braces, and the WWDC 2011 video on ARC mentions something about enclosing cases in braces. If you want to know why, check out that video—I can't remember off the top of my head. – FeifanZ Sep 27 '11 at 00:16
  • 87
    It's been a while, but I seem to remember something in the C standard that didn't allow variable assignment after a case statement because the code is not really inside of a block. By adding curly braces `{...}` after the `case` and before the `break`, everything inside is in a scoped block and will behave as expected. I've gotten to the point that I just automatically make a block out of my `case` statements to avoid this kind of problem. – Paul Sep 27 '11 at 00:16
  • 2
    I ran into the same issue. It is a horrible error message and a bug has been filed (which will be fixed in a future version of the compiler) to correct it. But, yes, the scoping rules within case statements in C are really very... odd. – bbum Sep 27 '11 at 04:12
  • 59
    This is occurring because you're declaring a new variable within the scope of a case. The compiler doesn't know how this variable should be scoped (does it belong to all of the switches cases or just the current case?) wrapping the case's implementation in brackets creates a scope for the variable to live within so the compiler can properly manage it's lifetime. – Shinohara Jul 06 '12 at 15:37
  • 1
    Note that this also can happen when declaring a variable within a block within a case statement with no curly braces. That was a head scratcher for a minute or two. =) – slycrel Jun 11 '14 at 17:16
  • +1 to slycrel... I *thought* I totally understood what this error meant, but I'm staring at the line for like several minutes saying, "But I'm NOT declaring a variable, dammit!" Ah, but I am declaring a variable within a block that I am passing as a parameter... and that counts as implicitly declaring a variable. Nice. – user435779 Oct 30 '14 at 17:58
  • Ditto all of the above, but note that, confusingly, declaring a variable in a case block will cause the error to appear at the beginning of the *following* case block, at least in my "sample of one". – Jerry Krinock May 28 '15 at 20:52
14

Hard to be sure without looking at the code, but it probably means there's some variable declaration going on inside the switch and the compiler can't tell if there's a clear path to the required dealloc point.

Flyingdiver
  • 2,142
  • 13
  • 18
9

There are 2 easy ways to solve this issue:

  • You are probably declaring variables. Move the declaration of the variables outside the switch statement
  • Put the whole case block in between curly brackets {}

The compiler can not calculate the code line when the variables are to be released. Causing this error.

Vincent
  • 4,342
  • 1
  • 38
  • 37
5

For me, the problem started on the middle of a switch and curly brackets did not worked out, unless you have to include {} IN ALL previous case statements. For me the error came when I had the statement

NSDate *start = [NSDate date];

in the previous case. After I deleted this, then all subsequent case statement came clean from the protected scope error message

Z. Zepos
  • 87
  • 1
  • 7
  • Same thing; case error in the middle. I only had to move the variable declaration above the switch (it wasn't case dependent). I did not have to add braces around the cases (this time). – eGanges Feb 13 '15 at 18:48
3

Before:

    case 2:
        NSDate *from = [NSDate dateWithTimeIntervalSince1970:1388552400];
        [self refreshContents:from toDate:[NSDate date]];
        break;

I moved NSDate definition before switch, and it fixed the compile problem:

NSDate *from;  /* <----------- */
switch (index) {
    ....
    case 2:
        from = [NSDate dateWithTimeIntervalSince1970:1388552400];
        [self refreshContents:from toDate:[NSDate date]];
        break;

}
Roozbeh Zabihollahi
  • 7,207
  • 45
  • 39
2

Declare the variables outside the switch, then instantiate them inside the case. That worked perfectly for me using Xcode 6.2

1
default:
        CellIdentifier = @"Cell";
        cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            ***initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];***
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
            }
        break;
    }

Note: Check! The syntax of the bold & italicized line. Rectify it and you are good to go.

Pochi
  • 13,391
  • 3
  • 64
  • 104
hemant_maverik
  • 539
  • 1
  • 4
  • 9
0

Surround with braces {} the code between the case statement and the break in each case. It worked on my code.

David
  • 165
  • 1
  • 8