setlocale works in iOS Simulator but fails on device - ios

Unlike the author of this previous question, I'm having the opposite problem. I'm attempting to make use of a component written in C++ in my iPad application that uses setlocale() from the standard C library. When running via the simulator (either i386 or x86_64), I'm able to set a locale successfully and get an expected return value:
(lldb) p (const char *)setlocale(2, "ja_JP")
(const char *) $1 = 0x000000010e776bd0 "ja_JP"
However, when running on a device (on either iOS8 or iOS9, on both armv7 and arm64 devices), this call always seems to fail and return null.
(lldb) p (const char *)setlocale(2, "ja_JP")
(const char *) $0 = 0x00000000
Actually setting the region and language on the iOS device doens't seem to make a difference either.
Is this an example of something like iOS9 preventing the use of sysctl(), or am I missing something bigger here?

This was actually answered on the Apple Dev Forums recently, sharing it here as well:
The problem here is not setlocale per se, but rather in reading the
locale in the first place. Notably, newlocale also returns NULL when
you call it with similar parameters. This fails because no C-style
locales are available to you on iOS. On the simulator this works
because the locale code picks up the locale data from OS X (in
/usr/share/locale). I’m not sure if this directory is populated on
iOS (I suspect not) but that doesn’t matter because the sandbox won’t
let your process get to it.

Related

How to reinstall / reset lldb?

My LLDB seems like broken by a plugin. Its output seems a little bit weird like this:
Process 771 stopped
* thread #1, stop reason = signal SIGSTOP
frame #0: 0x0000000100ac1000 cy-5Xn7dn.dylib`_dyld_start
cy-5Xn7dn.dylib`_dyld_start:
I don't know what cy-5Xn7dn.dylib is and I want to reinstall/reset my LLDB to fix this problem. Is there any possible way to reinstall or reset it?
Update:
This is otool information:
$ otool -l /usr/bin/lldb|grep " name"
name /usr/lib/dyld (offset 12)
name /usr/lib/libxcselect.dylib (offset 24)
name /usr/lib/libSystem.B.dylib (offset 24)
It looks like something is loading an alternative to the normal dynamic loader into the program you are running? I don’t think this is something lldb is doing, however. It is just relaying to you the dynamic library information that it got from the dynamic loader.
I’d first find that oddly named library and see if that tells you anything. You can use the lldb ‘image list <library_name>’ command to get the full path to the library. Is that in a place that maybe explains what it is?
It is possible to specify an alternate dynamic loader with the LC_DYLINKER command in the main binary. You might check the program you are debugging to see if it is doing that.
The DYLD_INSERT_LIBRARIES environment variable can also be used to force a program to load some other dylib. You should also make sure that isn’t being set. You can use ‘expr (char *) printenv(“DYLD_INSERT_LIBRARIES”)’ in lldb to check What it is in the app directly.

Cannot resolve enum values by name in Xcode debugger

With an enum typedef'd in a global header file used throughout my project, I am unable to refer to the individual enum values by name while using lldb in Xcode.
For example, if I am stopped at a breakpoint anywhere the enum type is available, and I try to evaluate something at the lldb prompt in Xcode (e.g. (lldb) p (int)EnumConstant), lldb complains:
error: use of undeclared identifier 'EnumConstant'
Furthermore, if I try to set a conditional breakpoint using an enum constant in the condition (e.g. right-click breakpoint in Xcode > Edit Breakpoint... > Condition: EnumConstant == someLocalVar), then Xcode complains every time it tries to evaluate that condition at that breakpoint:
Stopped due to an error evaluating condition of breakpoint 1.1: "EnumConstant == someLocalVar"
Couldn't parse conditional expression:
error: use of undeclared identifier 'EnumConstant'
Xcode's code completion popover even resolves a suggestion for the enum constant when I begin typing the name in the "Edit Breakpoint..." window, so Xcode itself doesn't have a problem resolving it.
Is there an option I can set in lldb or Xcode so that lldb maintains the enum identifiers after compilation? I'm assuming the enum constants get translated to their ordinal value during compilation, causing the executable to discard the identifiers, but thats just my naive speculation.
When I use the equivalent code in a simple GNU C program in Linux or Cygwin (minus the class definitions obviously), but using gcc/gdb instead of Xcode/lldb, I don't have these problems. It is able to resolve the enum values no problem.
I've created a tiny Xcode iPhone project to demonstrate what I mean. Using any of the enum_t constants below within the ViewController.m context (the for-loop is a good place to demo) will produce the same results.
ViewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
typedef enum
{
eZero, eOne, eTwo, eCOUNT
}
enum_t;
extern NSString const * const ENUM_STR[];
#end
ViewController.m:
#import "ViewController.h"
#implementation ViewController
NSString const * const ENUM_STR[eCOUNT] = { #"eZero", #"eOne", #"eTwo" };
- (void)viewDidLoad
{
[super viewDidLoad];
for (enum_t value = eZero; value < eCOUNT; ++value)
{
NSLog(#"%-8# = %d", ENUM_STR[value], value);
}
}
#end
This is a bug (fairly longstanding) in how the name->Debug Information lookup-accelerator tables for enums are built. While enum types are listed, enum values are not. That was surely done to save output debug info size - debug information gets quite big pretty quickly, and so there's a constant tension between the cost of adding more info and the utility of that more info. So far this one hasn't risen to the level of inclusion.
Anyway, doing a search through "all debug information for anything with a name that matches 'eZero'" is prohibitively slow even for decent sized projects, and gets really bad for large ones. So lldb always uses these name->Debug Info tables for its first level access.
Because the accelerator tables do contain the enum type by name (and more important for you typedefs by name as well), the workaround is to do:
(lldb) expr enum_t::eZero
(int) $0 = 0
Of course, if you have truly anonymous enums, then you are pretty much out of luck till this info gets added to the accelerator tables.
BTW, the Xcode symbol completion in the Debugger Console window is done using the Xcode SourceKit indexer, not lldb. So the completions offered from Xcode are not a reflection of lldb's knowledge of the program.
BBTW, gdb doesn't use compiler-made accelerator tables (these were an Apple extension up till the new DWARF 5 standard) but manually builds an index by scanning the debug info. That allows them to index whatever seems best to the debugger. OTOH, it makes debugger startup quite a bit slower for big projects.

What is accomplished by checking the address of a constant like SKStoreProductParameterAffiliateToken?

I have this code from a library I am using.
#ifdef __IPHONE_8_0
if (&SKStoreProductParameterAffiliateToken) {
if (self.affiliateToken) {
[appParameters setObject:self.affiliateToken forKey:SKStoreProductParameterAffiliateToken];
if (self.campaignToken) {
[appParameters setObject:self.campaignToken forKey:SKStoreProductParameterCampaignToken];
}
}
}
#endif
Xcode is saying that the first line will always evaluate to be true but what is this line doing exactly? I never saw a if with & and a constant in that way.
SKStoreProductParameterAffiliateToken is defined as
SK_EXTERN NSString * const SKStoreProductParameterAffiliateToken NS_AVAILABLE_IOS(8_0);
What is the developer trying to check, the address of a constant? Is he trying to check if the version of iOS has this constant defined and by doing that, he is trying to check the instruction inside the if should run? But he already has ifdef __IPHONE_8_0... (??!!)
I don't get it.
Anyway I am compiling for iOS 9.3, so I can delete the if and the ifdef, right?
It is a check to see if a weak-linked symbol is available. If the library/framework containing the symbol has been weakly linked and is not available its address will evaluate to NULL and the if condition will be false.
See Using Weakly Linked Methods, Functions, and Symbols in Apple's Using SDK-Based Development for full details.
#ifdef __IPHONE_8_0 checks if Xcode should compile code inside. Ohterwise older version of Xcode will show an error about unknown variable SKStoreProductParameterAffiliateToken.
But when using newer Xcode version (with iOS SDK 8+), we may still can set a lower minimum target for our project. In this case to avoid crash on devices with lower than iOS 8 version we should check first if variable, class, method or function exists.
In your case, we are checking if pointer to SKStoreProductParameterAffiliateToken is not NULL, which means app is currently running at least on iOS 8.

Why do we get the address of AVCaptureSessionInterruptionReasonKey in AVCam sample code?

I am reading this sample code (AVCam) about AVCaptureSession and etc. And I notice this following line (link to the code):
// In iOS 9 and later, the userInfo dictionary contains information
// on why the session was interrupted.
if ( &AVCaptureSessionInterruptionReasonKey ) {
...
}
The comment in the code make sense. But what doesn't make sense to me is why do we want to get the address of AVCaptureSessionInterruptionReasonKey. It is defined as the following (in AVCaptureSection.h):
AVF_EXPORT NSString *const AVCaptureSessionInterruptionReasonKey NS_AVAILABLE_IOS(9_0);
If the key is defined, how will its address be nil? If this key is not defined, the code will never be compiled, right? Could someone explain to me how this if statement work?
AVCaptureSessionInterruptionReasonKey was added in iOS 9.0. Such an if statement is needed only if your app also supports iOS 8 or earlier.
When the code is run on a device with iOS 9 or later, the value will be non-nil and the if statement will be true. On devices with iOS 8 or earlier, the value will be nil and the if statement will be false.
If your app only supports iOS 9 or later, there is no need for the if statement.
Read the SDK Compatibility Guide in the iOS docs for more details on this type of check.

iswalpha() in iOS doesn't return the same value on iOS that it does on MacOS

I have a problem about iswalpha() on iOS.
I am tuning my app in Xcode 4.5 and I tried to pass the Spanish character ú to iswalpha(). The xcode displays the int value of ú is 250.
When I tried to run the app on a real device, iswalpha() returns 0; but in the simulator (I run Xcode on a MacBook air with 10.8.2) it returns 1.
I guess the reason might be iOS has a different implementation of wide-character than does MacOS. What is the best way to resolve this?
Enhanced details:
UTF-16(unicode)encoding of Spanish character ú is 250 in int value. I think iswalpha()should return 1, as MACOS does, other than in iOS return a 0.
Dam new user could not post image here. so for UTF-16 encoding of ú please refer to :
http://www.fileformat.info/info/unicode/char/fa/index.htm
Well I can answer my own question now, as well as a development log in case I forgot this later:
It seems to be a fault of Apple's implementation of libc in iOS. The implementation of iswalpha() is incomplete considering letters in languages other than English. The specific letters(ú,á,ó,...) in different languages could not be recognized by iswalpha(), because they fall out of the 0x7F ASCII boundry, and for somehow it could not be recognized by iOS's locale processing functions, but obviously in different locale those should still be readable alphabet letters.
Some details about it:
iswalph() in iOS is tracked down to:
__DARWIN_CTYPE_static_inline int
__istype(__darwin_ct_rune_t _c, unsigned long _f)
{
#ifdef USE_ASCII
return !!(__maskrune(_c, _f));
#else /* USE_ASCII */
return (isascii(_c) ? !!(_DefaultRuneLocale.__runetype[_c] & _f)
: !!__maskrune(_c, _f));
#endif /* USE_ASCII */
}
and it is __maskrune(_c, _f)) that in the end returns 0.
It is understandable that Apple missed this point since, nobody will use iswalpha() in Objective-C. However it may still be useful to note this point for some porting projects. It was a widely used function so maybe important to many legacy projects that porting to iOS. Hope Apple could fix it in later release.
My workaround now to this problem is to have a wrapper function of iswalpha(), which handle these Latin letters by my own code. Now the app runs flawlessly in my iPhone!

Resources