Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

larswik

macrumors 68000
Original poster
Sep 8, 2006
1,552
11
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,

Incompatible pointer types initializing 'UILabel *' with an expression of type 'UIView *'

Just wondering for future reference what is happening there.

Thanks.
 
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!
 
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.
 
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
 
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.
 
I see what you are saying and that clears it up. I get it now.

Thanks.
 
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.

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.
 
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 ~
 
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?
 
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?

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.
 
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?
 
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?


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.
 
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.

When it is said that you cannot type cast objects, it is referring to this part of the C-spec:

Unless the type name specifies a void type, the type name shall specify qualified or
unqualified scalar type and the operand shall have scalar type.

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.
 
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.
 
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...
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.
 
There are several options:

Code:
((UILabel*)control).text = @"";
	  
UILabel* theLabel = (UILabel*)control;
theLabel.text = @"";

id control2 = [[UILabel alloc] init];
[control2 setText:@""];
 
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;
 
Code:
((UILabel*)control).text = @"";
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?

----------

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;
}
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?
 
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.
 
Last edited:
The point of your code is unclear (at least to me) so our answers were a little different. ...

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. ...
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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.