Object type Casting?

Discussion in 'iOS Programming' started by larswik, Jan 30, 2014.

  1. larswik macrumors 68000

    Joined:
    Sep 8, 2006
    #1
    I am using this line of code to gain access to a UILabel to change it's text values using a tag number. I asked before and I know you can not type cast objects, but this looks like it is type casting to me, is it?

    Code:
    UILabel *label = [COLOR="Red"](UILabel*)[/COLOR][self.view viewWithTag:1514];
    
    If I do not use that Type Casting then I get an error saying,

    Just wondering for future reference what is happening there.

    Thanks.
     
  2. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #2
    You're typecasting. What makes you think it's not doable?

    Your code looks horrendous for a different reason.

    What is 1514? It's a magic number.
     
  3. MattInOz macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #3
    So is the code in question from a View or a ViewController?
     
  4. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #4
    So it is Typecasting? I thought I read something a while back that you could not Typecast objects, but only primitive data types. It must be very limited to then. I can't typecast an NSString object to an NSFileManager object?

    When you add something to the view, like [self.view addView: myUIImageView]; it then becomes a generic view with a tag if you add a tag. Then to gain access to view in question you search the the views using the tag number. Is it because the view with tag is a generic view at this point and needs to be re identified as a UILabel in this case? That seems to be what it is doing?

    It's a simple question, but I thought you could not typecast objects.

    Thanks!
     
  5. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #5
    You're not changing it's type. It was always a UILabel. But Xcode doesn't know that, because viewWithTag: is declared as returning a pointer to a UIView. Which is true, because UILabel is a subclass of UIView. But you, as the person using it, know that not only is the object a UIView, but it's a UILabel, and by inserting the typecast you're telling Xcode about it, too.
     
  6. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #6
    I see. So when a UIView is added to the main view it looses all identity to what it's object was, and just becomes an added view with a tag in my case.

    So adding what looks to be a Typecast is really to just helper re identify what it originally was. Trying to add a different typecast to what it was would through an exception at run time or flat out give me an error right away.

    There is no conversion of what it was, just re identifying it.

    Thanks
     
  7. MattInOz macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #7
    The data backing your object always knows what class the object is and from that knows what classes it inherits from but the code doesn't always know that it relies on the return types of the method it has received the object from.

    It doesn't so much lose it's identity it's more a case that current code context can't tell it apart from a UIView or a subclass of UIView. You have to reintroduce or cast yourself back to your subClass if you want to use methods of the subclass.
     
  8. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #8
    I see what you are saying and that clears it up. I get it now.

    Thanks.
     
  9. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #9
    The typecast is removed entirely at compilation. If you end up with an error, it'll be a runtime error when you try to call a method on that object that it doesn't have.
     
  10. WhiteSponge macrumors member

    WhiteSponge

    Joined:
    Jan 31, 2014
    #10
    that's because XCode only knows that it's an UIView (which is correct as UILabel is subclass of it) but only u know that it's an UILabel so you have to use that to tell XCode ~
     
  11. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #11
    But the term typecast means to convert to something else, your casting to something different. This is more of a reminder to the UIView what it is a UILabel?
     
  12. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #12
    Typecasting does not convert anything. It tells the compiler "Trust me, I know what I'm doing."

    Think about this.

    A view controller has a content view. The content view can contain a variety of subviews. Labels, switches, buttons, whatever. Those subviews can have tags if you want.

    All of the objects you can add to a view controller's content view will be "subclasses" of UIView. They'll be UIView objets that also have other custom behaviors and features. Buttons can be clicked. Labels display text. Text fields can manage user-edited text. Switches can let the user choose an on or off state. Segmented controls let the user choose from one of several values. UIPicker objects let the user pick from a variety of different values, or even pick several different values. Etc, etc. All these things are UIView objects with additional custom behaviors.

    The method viewWithTag simply searches for a subview of the current view with a tag that matches the number you are asking for. The method doesn't care what kind of view object it is. It just treats it as a vanilla UIView Object. It might be a vanilla UIView, or it might be a button, or a switch, or something else.

    Since that method can't know which kind of object it's going to return, it just returns a pointer of type UIView. The object it's returning will be a UIView object or some subclass of UIView.

    If the object is a subclass of UIView and you know what type it is, you can use type casting to tell the compiler "I know you don't know what kind of view object this is, but I do. Trust me, its a UILabel".

    If you're wrong, and you try to set the text of the object, but it's really a UISwitch, you will crash, because a UISwitch does not have a text property. Essentially you lied to the compiler, so now your program dies.
     
  13. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #13
    I do see what you are saying and most of that I already understand. But take a look at this example in C.

    Code:
    {
        float x;
        x = (float) 11/4;
        printf("%f",x);
    }
    
    Here I took 2 integers and converted the result into a float. Is this not considered a conversion from int to float?
     
  14. Duncan C macrumors 6502a

    Duncan C

    Joined:
    Jan 21, 2008
    Location:
    Northern Virginia
    #14

    Numeric scalars are an exception. The compiler will actually generate code to CONVERT from/to the different types of integer and floating point data types.

    However you have to be very careful.

    In your example,

    Code:
        x = (float) 11/4;
    
    The compiler will first divide 11 by 4 using integer math. The result will be 2. Then it will convert the result to a floating point value of 2.0.

    It would be better to use code in this form:


    Code:
        x = 11/4.0;
    

    The C compiler will "promote" a value to float if any of the other terms are floats. By writing "4.0" the compiler treats 4 as a floating point constant, and will promote 11 to a floating point 11.0, do the math as floats, and then save the results to the float X

    You should buy and read the Kerrigan and Richie C book "The C Programming Language". It explains all this very clearly.

    Object types don't exist in C, but object variables are really pointers, and casting follows the same rules as casting any pointer variable.
     
  15. ElectricSheep macrumors 6502

    ElectricSheep

    Joined:
    Feb 18, 2004
    Location:
    Wilmington, DE
    #15
    When it is said that you cannot type cast objects, it is referring to this part of the C-spec:

    An object is not a scalar type, and you cannot use it as the type-name of a cast expression. However, a pointer to an object is a scalar type, and that is what you are doing here. In fact, the specific term is downcasting as you are casting from a base-type to a derived type. Some people think that there is nothing wrong with this, and others advocate avoiding downcasts as much as possible; an OOP design that depends on it is likely not the best approach.
     
  16. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #16
    I see what you guys are saying. This was not a big issues for me I just needed some clarification.

    Thanks a lot for taking the time to explain this out further.
     
  17. CiderHouse macrumors newbie

    Joined:
    Jan 6, 2012
    #17
    So sorry to bump an old topic, but I thought it prudent to continue a relevant topic rather than start a new one.

    I'm trying to implement an automatic UI creator, and would like to effect the creation within switch cases. However, with the scoping issues of switch statements, declaring an object within a single case does not carry it beyond that scope. As such, I was advised to declare a common UIView object before the switch block, and then recast it to the appropriate control type within each case.

    However, the recast objects don't seem to inherit the properties of their recast types. Perhaps this code would explain in better:

    Code:
    UIView *control = nil;
    switch (objectType) {
    
      case label:   //label is an integer constant
      {
        control = [[UILabel alloc] init];
    
        //error: Property 'text' not found on object of type 'UIView *'
        control.text = @"Something...";
      }
      break;
    
      case button:  //button is an integer constant
      {
        control = [[UIButton alloc] init];
    
        //error: Property 'titleLabel' not found on object of type 'UIView *'
        control.titleLabel.textAlignment = NSTextAlignmentCenter;
      }
      break;    
    
      default:
        break;
    }
    Have I done something wrong, or is this simply not possible? :confused:

    Thank you.
     
  18. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #18
    There are several options:

    Code:
    ((UILabel*)control).text = @"";
    	  
    UILabel* theLabel = (UILabel*)control;
    theLabel.text = @"";
    
    id control2 = [[UILabel alloc] init];
    [control2 setText:@""];
     
  19. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #19
    You could structure it like this:
    Code:
    UIView *control = nil;
    switch (objectType) {
    
      case label:   //label is an integer constant
      {
        UILabel *ui = [[UILabel alloc] init];
        control = ui;
        ui.text = @"Something...";
      }
      break;
    
      case button:  //button is an integer constant
      {
        UIButton *ui = [[UIButton alloc] init];
        control = ui;
        ui.titleLabel.textAlignment = NSTextAlignmentCenter;
      }
      break;    
    
      default:
        break;
    }
    Note the absence of type-casts.

    If the code in a single 'case' block is siginificant, you can factor out the block into a static function that returns a UIButton*, or a UILabel*, etc. Then the 'case' would look like this:
    Code:
      case button:  //button is an integer constant
        control = makeButtonOfInterest();
        break;    
    
     
  20. CiderHouse macrumors newbie

    Joined:
    Jan 6, 2012
    #20
    I knew I had to cast it somehow, but just didn't know how. Thank you.

    So, the control object remains of UIView type, although it has been cast with UILabel properties?

    And dot notation would not be possible? Only methods?

    ----------

    Thank you for your answer.

    Your approach seems a little different from PhoneyDeveloper's, which casts the UIView object; you seem to be assigning one object to another:
    Code:
    control = ui;
    Is this just a pointer assignment, or does the control object become a UIlabel?
     
  21. PhoneyDeveloper, May 24, 2015
    Last edited: May 24, 2015

    PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #21
    The point of your code is unclear (at least to me) so our answers were a little different.

    Objects do not change their type when pointers are typecast. As mentioned upthread, scalar types can change their type when typecast.

    If you typecast an object pointer this tells the compiler to let you send messages that it already knows are valid for the typecast type. However, the object must really respond to those messages or you'll get runtime errors. The viewWithTag: method is an example. It returns a type of UIView because the actual type isn't known to the compiler at compile time. You will usually need to typecast the returned view in order to use it. I'll say that I haven't used viewWithTag in years. I always use IBOutlets or @properties instead these days.

    If your goal is to have a factory method that returns objects of various types you would normally create those objects inside by alloc/init and the return type would be a shared base class type, very much like viewWithTag.
     
  22. CiderHouse macrumors newbie

    Joined:
    Jan 6, 2012
    #22
    You're right; this is for a factory method for dynamically creating UI elements.

    The concept is pretty clear to me now. Thank you for taking the time to explain it.

    And thank you for the heads-up about the viewWithTag method; I wasn't aware of that.
     

Share This Page