Question

Problem Description

I have a function StdString ShowLockScreen() in this function I call activateViewController function which shows some UI where user must enter PIN, just after calling activateViewController function I want to lock all processes until user will enter his PIN and press OK button on opened UI. Below you can see code which I try

Source code in iOS

StdString ShowLockScreen() 
{
    // Create a lock.
    NSLock* theLock = [[NSLock alloc] init];
    // Create a UI in which user must enter his PIN.
    PinLockController* controller = [[PinLockController alloc] initWithStyle:PinLockTypeSet];
    // Set delegate. 
    controller.delegate = m_Context;

    // !!! Here I show a UI and just after that I lock my lock in order code stop executing there.
    [controller activateViewController:nil];

    @synchronized(theLock) {
        [theLock lock];
    }

    NSLog(@"User in UI unlock the lock");
}

I want that my code stops then I call [theLock lock]; and after I will call [theLock unlock]; from my UI and code will continue executing. But it doesn't work in my case.

Source code in Android

I have write similar application in Android and here is code. I want to write same in iOS but I can;t find solution

Intent intent = new Intent(mCtx, SoftPinActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

SharedObject lock = new SharedObject("");
int lockId = SharedObject.acquireLockId(lock);
Logger.i(TAG, "lockId = " + lockId);
intent.putExtra(SharedObject.LOCK_ID, lockId);
intent.putExtra(SoftPinActivity.UI_ID, style);

synchronized (lock) {
   mCtx.startActivity(intent);
   try {
          Logger.i(TAG, "lock.wait()...");
          lock.wait();
   } catch (InterruptedException e) {
          e.printStackTrace();
          Logger.i(TAG, "InterruptedException");
   }
}
Logger.i(TAG, "lock.wait()...done");
SharedObject.releaseLockId(lockId);

String pin = lock.object();

Researches

I think I must use

NSCondition* condLock = [[NSCondition alloc] init];
[condLock wait];

and

[condLock signal];

but how to use this in my code ?

Was it helpful?

Solution 3

Okay I found solution to this issue, below you can see implemented function and line by line description.

StdString ShowLockScreen() 
{
    // Create NSCondition lock object.
    NSCondition* conditionLock = [[NSCondition alloc] init];

    // Here I create my UI which must ask user to enter PIN.
    PinLockController* controller = [[PinLockController alloc] initWithStyle:PinLockTypeSet];
    controller.delegate = m_Context;

    // Here I lock the thread but not main thread (this is very important) I start
    // ShowLockScreen function in new thread and lock it.
    [conditionLock lock];

    dispatch_sync(dispatch_get_main_queue(), ^{
        // I call function which shows my UI in main thread as UI can be shown 
        // only in MAIN THREAD. (This is important too.)
        [controller ShowLockController:conditionLock];
    });

    // Then I set lock to wait, how you can see I pass conditionLock as an 
    // argument to ShowLockController function in that function when user
    // enter his PIN and press okay button I call [conditionLock signal];
    // and my code code here after wait and continue executing.
    [conditionLock wait];

    NSLog(@"Come here then I call [conditionLock signal]!!!")
}

OTHER TIPS

Answer to problem

You can lock threads using NSLock, but in your situation, this doesn't seem to be applicable. The reason being is that locking is primarily used to provide thread safety when data is accessed from multiple threads. What you're asking for is a domain level lock, which prevents the user from using the application unless they've typed in their PIN. These two concepts share the word "lock", but they're entirely different in their implementation. If you were to use NSLock and its related counterparts, you're forcing your implementation into separate threads purely to block user interaction, and risk complicating your project and pains in debugging (deadlocks much?).

Suggested solution

As the concept is a domain level locking mechanism, I suggest we keep it this way for its implementation. If you want it to be analogous to Android, then you'd need to create your own concept of a 'SharedObject' that everything else queries. If this object were to say "The user hasn't unlocked the application", then nothing will process. This keeps you away from manually managing threads, and frees threads up for when you really need them most (asynchronous processing for example).

To implement this object, lets call it a UserContext, which is available as a singleton. How to implement this sharedInstance can be seen here.

Once you have that, then you can add various properties to it that are global throughout the application (and by the suggestion of the name, has all global properties that belong to a particular user). One of these properties is whether the user has the app locked or not:

[[UserContext sharedInstance] isLocked] // Returns BOOL

Using this throughout your application, you can then control (at the domain concept level), whether a method can compute something or not (naturally, you'll need to make UserContext thread safe, as it could be queried anywhere at any time). It would make it clear to the developer reading the code, that a certain method can not do anything unless the user has unlocked the app. To stop

Side notes

I want that my code stops then I call [theLock lock]; and after I will call [theLock unlock]; from my UI and code will continue executing.

Do not, under any circumstances, lock the UI thread. In a published app, the watchdog will kill your app, and it will effectively crash.

ViTo, as much I concerned with the NSLock, we use it in the case of multi-threading in which we lock a particular thread and force that upto that not unlock, none other thread become active or to do his required task. So, may be what we can do that first of all we start all of your processes in the terms of thread and at that point when you try to open your UI we call 'lock' and when user pressed the button after inputting the text-box then we call 'unlock'. But, for this we've to sure that this thread has high priority. That's what I'm thinking right now, but really try this with my sample code and will update you accordingly.

Check that part of code:

+(void)aMethod:(id)param{
 int x;
 for(x=0;x<50;++x)
 {enter code here
 [lock lock];
 printf("Object Thread says x is %i\n",x);
 usleep(1);
 [lock unlock];
 }
}

- (void)viewDidLoad
{    
 int x;
 lock = [[NSLock alloc] init];
 [NSThread detachNewThreadSelector:@selector(aMethod:) toTarget:[MViewController class] withObject:nil]; 
 for(x=0;x<50;++x)
 {
 [lock lock];
 printf("Main thread says x is %i\n",x);
 usleep(10000);
 printf("Main thread lets go %i\n",x);
[lock unlock];
 usleep(100);
 }
 printf("Now getting the process");
[super viewDidLoad];
}

Check the log you'll get what you want. Hope, it's what you need. For any concern, shout-over me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top