16
votes

I have IBOutlet UILabel *label;

and I want to do this

UILabel *label = [titleLabel copy];
label.text = @"Clone";
titleLabel.text = @"Original";
NSLog(@"label : %@, title : %@",label.text,titleLabel.text);

and this throw exception

* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UILabel copyWithZone:]: unrecognized selector sent to instance 0x6a4a450' * First throw call stack: (0x126f052 0x1823d0a 0x1270ced 0x11d5f00 0x11d5ce2 0x1271bd9 0x2ed6 0x1270e1a 0x2851 0x28264e 0x1e2a73 0x1e2ce2 0x1e2ea8 0x1e9d9a 0x24af 0x1ba9d6 0x1bb8a6 0x1ca743 0x1cb1f8 0x1beaa9 0x215cfa9 0x12431c5 0x11a8022 0x11a690a 0x11a5db4 0x11a5ccb 0x1bb2a7 0x1bca9b 0x21c2 0x2135)

5
youcan't, UILabel doesn't conform to NSCopying protocoluser971401
but i have another solution ?Igor Bidiniuc
yes, alloc/init a new label, set its frame, textuser971401
thanks, I thought that is possible with copy or anything another :)Igor Bidiniuc

5 Answers

25
votes

There is no public Apple API to deep copy a UILabel. Your best bet is to make a helper method which copies all the parts you care about.

- (UILabel *)deepLabelCopy:(UILabel *)label {
    UILabel *duplicateLabel = [[UILabel alloc] initWithFrame:label.frame];
    duplicateLabel.text = label.text;
    duplicateLabel.textColor = label.textColor;
    // etc... anything else which is important to your ULabel

    return [duplicateLabel autorelease];
}

If you want to use it all over your code base you can change it to a static method and put it in some sort of utility class. If you named the class LabelUtils you could do something like...

+ (UILabel *)deepLabelCopy(UILabel *)label {
    // ...
}

and would be called using UILabel *dupLabel = [LabelUtils deepLabelCopy:origLabel];

15
votes

I recommend using a merged version of Answer 1 and Answer 2:

- (UILabel *)copyLabel:(UILabel *)label {
    NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject: label];
    UILabel* copy = [NSKeyedUnarchiver unarchiveObjectWithData: archivedData];
    return copy;
}

Then simply use something like

UILabel* labelcopy = [self copyLabel:originalLabel];

in your code.

13
votes

UILabel does not conform to NSCopying, so you cannot make a copy via -copy.

But it does conform to NSCoding, so you can archive the current instance, then unarchive a 'copy'.

NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject: label];
UILabel *labelCopy =   [NSKeyedUnarchiver unarchiveObjectWithData: archivedData];

Afterwards, you'll have to assign any additional properties that weren't carried over in the archive (e.g. the delegate) as necessary.

8
votes

Swift 3 Solution

I created it as an extension to the UILabel.

extension UILabel {
    func createCopy() -> UILabel {
        let archivedData = NSKeyedArchiver.archivedData(withRootObject: self)
        return NSKeyedUnarchiver.unarchiveObject(with: archivedData) as! UILabel
    }
}

How to use

let anotherNameLabel = nameLabel.createCopy()

Additional Info - How does this work?

NSKeyedArchiver will take an object from memory and convert it to text. "Keyed" means it uses words to describe the properties of this object, like "LabelFrame", "LabelText", etc. (These are fake keys.) This also called Serialization in other technologies.

NSKeyedUnarchiver does the opposite. It will take that text and build an object. Here we take that object (Any?) and convert it to a UILabel.

0
votes

I solved it this way and wanted to post it for easy copy and pasting if you were thinking of doing the same.

func makeCopy() -> UILabel {

  let label = UILabel(frame: frame)
  label.text = text
  label.font = font
  label.textColor = textColor
  label.shadowColor = shadowColor
  label.shadowOffset = shadowOffset
  label.textAlignment = textAlignment
  label.lineBreakMode = lineBreakMode
  label.attributedText = attributedText
  label.highlightedTextColor = highlightedTextColor
  label.isHighlighted = isHighlighted
  label.isUserInteractionEnabled = isUserInteractionEnabled
  label.isEnabled = isEnabled
  label.numberOfLines = numberOfLines
  label.adjustsFontSizeToFitWidth = adjustsFontSizeToFitWidth
  label.baselineAdjustment = baselineAdjustment
  label.minimumScaleFactor = minimumScaleFactor
  label.allowsDefaultTighteningForTruncation = allowsDefaultTighteningForTruncation
  label.preferredMaxLayoutWidth = preferredMaxLayoutWidth

  return label
}