how to collect system info in osx using objective c

前端 未结 5 1100
予麋鹿
予麋鹿 2021-02-01 10:56

Is there any method / API defined to collect system info in osx. I want to write utility which will collect hardware information like CPU,RAM,Network adapter. Any idea ? Thanks

5条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-02-01 11:11

    System Profiler is nice and will output an XML for some slow file I/O and also let's depend on another process to complete before getting the desired information. Well if I put it this way, is System Profiler really the best option and answer for this question? I think not (IMO).

    Here is how I do it. The header are readonly properties of the private readwrite properties. The category methods are pretty straight forward, but if anyone has a question then post and I will answer.

    #import 
    #import 
    
    @interface VarSystemInfo ()
    @property (readwrite, strong, nonatomic) NSString *sysName;
    @property (readwrite, strong, nonatomic) NSString *sysUserName;
    @property (readwrite, strong, nonatomic) NSString *sysFullUserName;
    @property (readwrite, strong, nonatomic) NSString *sysOSName;
    @property (readwrite, strong, nonatomic) NSString *sysOSVersion;
    @property (readwrite, strong, nonatomic) NSString *sysPhysicalMemory;
    @property (readwrite, strong, nonatomic) NSString *sysSerialNumber;
    @property (readwrite, strong, nonatomic) NSString *sysUUID;
    @property (readwrite, strong, nonatomic) NSString *sysModelID;
    @property (readwrite, strong, nonatomic) NSString *sysModelName;
    @property (readwrite, strong, nonatomic) NSString *sysProcessorName;
    @property (readwrite, strong, nonatomic) NSString *sysProcessorSpeed;
    @property (readwrite, strong, nonatomic) NSNumber *sysProcessorCount;
    @property (readonly,  strong, nonatomic) NSString *getOSVersionInfo;
    
    - (NSString *) _strIORegistryEntry:(NSString *)registryKey;
    - (NSString *) _strControlEntry:(NSString *)ctlKey;
    - (NSNumber *) _numControlEntry:(NSString *)ctlKey;
    - (NSString *) _modelNameFromID:(NSString *)modelID;
    - (NSString *) _parseBrandName:(NSString *)brandName;
    @end
    
    static NSString* const kVarSysInfoVersionFormat  = @"%@.%@.%@ (%@)";
    static NSString* const kVarSysInfoPlatformExpert = @"IOPlatformExpertDevice";
    
    static NSString* const kVarSysInfoKeyOSVersion = @"kern.osrelease";
    static NSString* const kVarSysInfoKeyOSBuild   = @"kern.osversion";
    static NSString* const kVarSysInfoKeyModel     = @"hw.model";
    static NSString* const kVarSysInfoKeyCPUCount  = @"hw.physicalcpu";
    static NSString* const kVarSysInfoKeyCPUFreq   = @"hw.cpufrequency";
    static NSString* const kVarSysInfoKeyCPUBrand  = @"machdep.cpu.brand_string";
    
    static NSString* const kVarSysInfoMachineNames       = @"MachineNames";
    static NSString* const kVarSysInfoMachineiMac        = @"iMac";
    static NSString* const kVarSysInfoMachineMacmini     = @"Mac mini";
    static NSString* const kVarSysInfoMachineMacBookAir  = @"MacBook Air";
    static NSString* const kVarSysInfoMachineMacBookPro  = @"MacBook Pro";
    static NSString* const kVarSysInfoMachineMacPro      = @"Mac Pro";
    
    #pragma mark - Implementation:
    #pragma mark -
    
    @implementation VarSystemInfo
    
    @synthesize sysName, sysUserName, sysFullUserName;
    @synthesize sysOSName, sysOSVersion;
    @synthesize sysPhysicalMemory;
    @synthesize sysSerialNumber, sysUUID;
    @synthesize sysModelID, sysModelName;
    @synthesize sysProcessorName, sysProcessorSpeed, sysProcessorCount;
    
    #pragma mark - Helper Methods:
    
    - (NSString *) _strIORegistryEntry:(NSString *)registryKey {
    
        NSString *retString;
    
        io_service_t service =
        IOServiceGetMatchingService( kIOMasterPortDefault,
                                     IOServiceMatching([kVarSysInfoPlatformExpert UTF8String]) );
        if ( service ) {
    
            CFTypeRef cfRefString =
            IORegistryEntryCreateCFProperty( service,
                                             (__bridge CFStringRef)registryKey,
                                             kCFAllocatorDefault, kNilOptions );
            if ( cfRefString ) {
    
                retString = [NSString stringWithString:(__bridge NSString *)cfRefString];
                CFRelease(cfRefString);
    
            } IOObjectRelease( service );
    
        } return retString;
    }
    
    - (NSString *) _strControlEntry:(NSString *)ctlKey {
    
        size_t size = 0;
        if ( sysctlbyname([ctlKey UTF8String], NULL, &size, NULL, 0) == -1 ) return nil;
    
        char *machine = calloc( 1, size );
    
        sysctlbyname([ctlKey UTF8String], machine, &size, NULL, 0);
        NSString *ctlValue = [NSString stringWithCString:machine encoding:[NSString defaultCStringEncoding]];
    
        free(machine); return ctlValue;
    }
    
    - (NSNumber *) _numControlEntry:(NSString *)ctlKey {
    
        size_t size = sizeof( uint64_t ); uint64_t ctlValue = 0;
        if ( sysctlbyname([ctlKey UTF8String], &ctlValue, &size, NULL, 0) == -1 ) return nil;
        return [NSNumber numberWithUnsignedLongLong:ctlValue];
    }
    
    - (NSString *) _modelNameFromID:(NSString *)modelID {
    
        /*!
         * @discussion Maintain Machine Names plist from the following site
         * @abstract ref: http://www.everymac.com/systems/by_capability/mac-specs-by-machine-model-machine-id.html
         *
         * @discussion Also info found in SPMachineTypes.plist @ /System/Library/PrivateFrameworks/...
         *             ...AppleSystemInfo.framework/Versions/A/Resources
         *             Information here is private and can not be linked into the code.
         */
    
        NSDictionary *modelDict = [[NSBundle mainBundle] URLForResource:kVarSysInfoMachineNames withExtension:@"plist"].serialPList;
        NSString *modelName = [modelDict objectForKey:modelID];
    
        if ( !modelName ) {
    
            if ( [modelID.lowercaseString hasPrefix:kVarSysInfoMachineiMac.lowercaseString] ) return kVarSysInfoMachineiMac;
            else if ( [modelID.lowercaseString hasPrefix:kVarSysInfoMachineMacmini.noWhitespaceAndLowerCaseString] )    return kVarSysInfoMachineMacmini;
            else if ( [modelID.lowercaseString hasPrefix:kVarSysInfoMachineMacBookAir.noWhitespaceAndLowerCaseString] ) return kVarSysInfoMachineMacBookAir;
            else if ( [modelID.lowercaseString hasPrefix:kVarSysInfoMachineMacBookPro.noWhitespaceAndLowerCaseString] ) return kVarSysInfoMachineMacBookPro;
            else if ( [modelID.lowercaseString hasPrefix:kVarSysInfoMachineMacPro.noWhitespaceAndLowerCaseString] )     return kVarSysInfoMachineMacPro;
            else return modelID;
    
        } return modelName;
    }
    
    - (NSString *) _parseBrandName:(NSString *)brandName {
    
        if ( !brandName ) return nil;
    
        NSMutableArray *newWords = [NSMutableArray array];
        NSString *strCopyRight = @"r", *strTradeMark = @"tm", *strCPU = @"CPU";
    
        NSArray *words = [brandName componentsSeparatedByCharactersInSet:[[NSCharacterSet alphanumericCharacterSet] invertedSet]];
    
        for ( NSString *word in words ) {
    
            if ( [word isEqualToString:strCPU] )       break;
            if ( [word isEqualToString:@""] )          continue;
            if ( [word.lowercaseString isEqualToString:strCopyRight] ) continue;
            if ( [word.lowercaseString isEqualToString:strTradeMark] ) continue;
    
            if ( [word length] > 0 ) {
    
                NSString *firstChar = [word substringToIndex:1];
                if ( NSNotFound != [firstChar rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]].location ) continue;
    
                [newWords addObject:word];
    
        } } return [newWords componentsJoinedByString:@" "];
    }
    
    - (NSString *) getOSVersionInfo {
    
        NSString *darwinVer = [self _strControlEntry:kVarSysInfoKeyOSVersion];
        NSString *buildNo = [self _strControlEntry:kVarSysInfoKeyOSBuild];
        if ( !darwinVer || !buildNo ) return nil;
    
        NSString *majorVer = @"10", *minorVer = @"x", *bugFix = @"x";
        NSArray *darwinChunks = [darwinVer componentsSeparatedByCharactersInSet:[NSCharacterSet punctuationCharacterSet]];
    
        if ( [darwinChunks count] > 0 ) {
    
            NSInteger firstChunk = [(NSString *)[darwinChunks objectAtIndex:0] integerValue];
            minorVer = [NSString stringWithFormat:@"%ld", (firstChunk - 4)];
            bugFix = [darwinChunks objectAtIndex:1];
            return [NSString stringWithFormat:kVarSysInfoVersionFormat, majorVer, minorVer, bugFix, buildNo];
    
        } return nil;
    }
    
    #pragma mark - Initalization:
    
    - (void) setupSystemInformation {
    
        NSProcessInfo *pi = [NSProcessInfo processInfo];
    
        self.sysName = [[NSHost currentHost] localizedName];
        self.sysUserName = NSUserName();
        self.sysFullUserName = NSFullUserName();
        self.sysOSName = pi.strOperatingSystem;
        self.sysOSVersion = self.getOSVersionInfo;
        self.sysPhysicalMemory = [[NSNumber numberWithUnsignedLongLong:pi.physicalMemory] strBinarySizeMaxFractionDigits:0];
        self.sysSerialNumber = [self _strIORegistryEntry:(__bridge NSString *)CFSTR(kIOPlatformSerialNumberKey)];
        self.sysUUID = [self _strIORegistryEntry:(__bridge NSString *)CFSTR(kIOPlatformUUIDKey)];
        self.sysModelID = [self _strControlEntry:kVarSysInfoKeyModel];
        self.sysModelName = [self _modelNameFromID:self.sysModelID];
        self.sysProcessorName = [self _parseBrandName:[self _strControlEntry:kVarSysInfoKeyCPUBrand]];
        self.sysProcessorSpeed = [[self _numControlEntry:kVarSysInfoKeyCPUFreq] strBaseTenSpeedMaxFractionDigits:2];
        self.sysProcessorCount = [self _numControlEntry:kVarSysInfoKeyCPUCount];
    }
    
    - (id) init {
    
        if ( (self = [super init]) ) {
    
            [self setupSystemInformation];
    
        } return self;
    }
    
    @end
    

    Enjoy!

    P.S. I load all the property values during init so as to avoid multiple system calls && because its cheap && all values should be fairly static.

    P.P.S. I also load a MachineNames plist that I created, but I know its my own process only that has access to it and the comment describes where I get the information.

提交回复
热议问题