If this is the right way to use a customised string property in Objective C, why can’t I extract the correct numeric value?
Asked Answered
S

2

2

I am revising an early project where I use tags to identify 1-of-5, 1-of-16 or 1-of-10 UIButtons. I want to replace the tags with a customised property based on my understanding of this answer.

The property called myInfo consists of a string followed by an integer. This may well be a tag by another name but it makes a message source uniquely identifiable in a way that a simple integer tag does not, clearing magic numbers from my code and, hopefully, improving the documentation.

The property is created using a category

UIView+CustomProperties.m

    #import "UIView+CustomProperties.h"

    @implementation UIView (MyInfo)

    -(void)setMyInfo:(id)info
    {
        objc_setAssociatedObject(self, "_myInfo", info, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }

    -(id)myInfo
    {
        return objc_getAssociatedObject(self, "_myInfo") ;
    }

    @end

And myInfo works when I import objc/runtime.h

UIView+CustomProperties.

    #import <objc/runtime.h>

    @interface UIView (MyInfo)
    @property ( nonatomic, strong ) id myInfo;

    @end

I call the category from the method (below) in the UIView where I create several sets of buttons.

    // define type and number of 5, 16 or 10 buttons

    switch (buttonCount) {
        case 5:
            roundButton.myInfo = [NSString stringWithFormat:@"transpose index %i", i ];
            break;
        case 16:
            roundButton.myInfo = [NSString stringWithFormat:@"player index %i", i ];
            break;
        case 10:
            roundButton.myInfo = [NSString stringWithFormat:@"note index %i", i ];
            break;
        default:
            roundButton.myInfo = @“orphan button“;
        break;
   }

To identify a message source I have tried to strip away all non-numeric characters from myInfo using this method. However a problem appears in my selector method forButtons as I attempt to remove non-numeric characters

- (void)fromButtons:(UIButton*)button                          {
    NSLog(@"Button %ld tapped", (long int)[button tag]);
    NSLog(@"first, %@", button.myInfo);

    NSString *newString = [[button.myInfo componentsSeparatedByCharactersInSet:
                        [[NSCharacterSet decimalDigitCharacterSet] invertedSet]]
                       componentsJoinedByString:@""];

    NSLog(@"then, %@", newString);
    NSLog(@"and %li", (long int)newString);

When I build and run and press button 1, the NSLog statements above produce the following log

    2017-05-25 18:27:33.147 SatGam3[930:607301] Button 1 tapped
    2017-05-25 18:27:33.147 SatGam3[930:607301] first, transpose index 1
    2017-05-25 18:27:33.148 SatGam3[930:607301] then, 1
    2017-05-25 18:27:33.148 SatGam3[930:607301] and 2070247168

Note that the long int value for the original tag is correct i.e. 1 whereas the long int recovered from the customised property is 2070247168.

Q.1 Firstly, is this approach correct ?

Q.2 If so, can someone please explain why am I extracting a 9-digit numeric value from myInfo ?

Swagman answered 25/5, 2017 at 10:46 Comment(0)
C
3

First, a problem that has nothing to do with your problem: Your use of "_myInfo" as the key here is slightly dangerous. In practice you're going to get away with it, but it relies on a compiler optimization that isn't promised. You're betting that the compiler (and possibly the linker) will ensure that all copies of the same constant string refer to the same memory location in the binary. That happens to be true, but it's not part of the language. Use a selector instead.

But that's not your problem. Your problem is this:

NSLog(@"and %li", (long int)newString);

newString is (unsurprisingly) an NSString*. So this points the address of that string. If you want to convert this into a number, you'll want to call -intValue on it.

That said, I wouldn't encode this data as a string. Encode it as a data object:

@interface ButtonInfo
@property (copy) NSString *name;
@property (assign) NSInteger index;
@end

(or name could be an enum if there are fixed set of them)

If you want to make this easier to read, add a -description method. Use the type system; it's there to help you. Don't try to encode a complicated type into a string.

Cristycriswell answered 25/5, 2017 at 12:28 Comment(1)
Rod, this has to be the accepted answer. Every solution offered addressed the problem associated with using NSString, but this answer also confirms what I suspected viz. that it might be better to encode information another way. Even without -description, it is already clearer with a separate button property for *name and index. Thanks.Swagman
F
1

Use below line of code :

NSLog(@"and %li", [newString intValue]);

Your approach is correct.

Furan answered 25/5, 2017 at 12:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.