I am trying to convert some Objective C code to Swift and can't manage to do it right with subscripting.
This is the method I am trying to migrate to Swift:
- (NSArray *)rangesOfSubstringAlphaNumeric:(NSString *)substring rangesLimit:(NSUInteger)rangesLimit {
NSAssert(rangesLimit, #"A range limit grather than 0 must be specified");
if (!substring.length) {
return nil;
}
static NSCharacterSet * restrictedCharacters = nil;
if (!restrictedCharacters) {
restrictedCharacters = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
}
NSArray * substrings = [substring componentsSeparatedByCharactersInSet:restrictedCharacters];
NSMutableArray * allRanges = [NSMutableArray array];
NSString *searchedString = self;
for (NSString *stringToMatch in substrings) {
if (![stringToMatch isEqualToString:#""]) {
NSRange aRange;
NSUInteger lastLocation = 0;
NSUInteger foundRanges = 0;
while (foundRanges++ < rangesLimit &&
(aRange = [searchedString localizedStandardRangeOfString:stringToMatch]).location != NSNotFound) {
searchedString = [searchedString substringFromIndex:aRange.location + aRange.length];
aRange.location = aRange.location + lastLocation;
lastLocation = aRange.location + aRange.length;
[allRanges addObject:[NSValue valueWithRange:aRange]];
}
}
}
return allRanges.count ? [allRanges copy] : nil;
}
I got stuck on the subscripting part since it seems I cannot assign integer values to Indexes and conversion from Index to Int is out of hand for me I'm kind of stuck, this is what I managed to do:
func rangesOfAlphanumeric(substring: String, limit: UInt) -> [Range<String.Index>] {
guard limit > 0, !substring.isEmpty else {
if limit == 0 {
assert(false, "limit must be greather than 0")
}
return []
}
var searchedString = self
let substrings = substring.components(separatedBy: NSCharacterSet.restricted)
for stringToMatch in substrings {
if !stringToMatch.isEmpty {
// var aRange: Range<String.Index>?
// var lastLocation: UInt = 0
// var foundRanges: UInt = 0
// while foundRanges < limit,
// let tempRange = searchedString.localizedStandardRange(of: stringToMatch),
// !tempRange.isEmpty {
//
// searchedString = String(searchedString[tempRange.upperBound...])
// if let lastLocation = lastLocation {
// aRange = temp
// }
// }
}
}
}
UPDATE: Solution below.
Managed to resolve the issue using the ranges function posted here:
func rangesOfAlphanumeric(substring: String) -> [Range<String.Index>] {
var searchedString = self
let substrings = substring.components(separatedBy: NSCharacterSet.restricted)
return substrings.compactMap { (stringToMatch) -> [Range<String.Index>]? in
guard !stringToMatch.isEmpty else {
return nil
}
let ranges = searchedString.ranges(of: stringToMatch, options: [
.diacriticInsensitive,
.caseInsensitive
])
if let lastRange = ranges.last {
searchedString = String(searchedString[index(after: lastRange.upperBound)])
}
return ranges
}.flatMap{$0}
}
I created this repo with swift 5 is very easy to use
all is already set up. you have just to change the IAP ids
The Github repo
I am looking for some help with dropping/skipping FFmpeg frames. The project I am working on streams live video which when the app goes into the background, upon returning to an active state the video stream spends a long time catching up by fast forwarding itself to the current frame. This isn't ideal and what I am aiming to achieve is have the app immediately jump to the most recent frame.
What I need to do is drop the amount of frames that are being fast-forwarded in order to catch up to the most recent frame. Is this possible? Here is my current code which decodes the frames:
- (NSArray *) decodeFrames: (CGFloat) minDuration
{
NSMutableArray *result = [NSMutableArray array];
#synchronized (lock) {
if([_reading integerValue] != 1){
_reading = [NSNumber numberWithInt:1];
#synchronized (_seekPosition) {
if([_seekPosition integerValue] != -1 && _seekPosition){
[self seekDecoder:[_seekPosition longLongValue]];
_seekPosition = [NSNumber numberWithInt:-1];
}
}
if (_videoStream == -1 &&
_audioStream == -1)
return nil;
AVPacket packet;
CGFloat decodedDuration = 0;
CGFloat totalDuration = [TimeHelper calculateTimeDifference];
do {
BOOL finished = NO;
int count = 0;
while (!finished) {
if (av_read_frame(_formatCtx, &packet) < 0) {
_isEOF = YES;
[self endOfFileReached];
break;
}
[self frameRead];
if (packet.stream_index ==_videoStream) {
int pktSize = packet.size;
while (pktSize > 0) {
int gotframe = 0;
int len = avcodec_decode_video2(_videoCodecCtx,
_videoFrame,
&gotframe,
&packet);
if (len < 0) {
LoggerVideo(0, #"decode video error, skip packet");
break;
}
if (gotframe) {
if (!_disableDeinterlacing &&
_videoFrame->interlaced_frame) {
avpicture_deinterlace((AVPicture*)_videoFrame,
(AVPicture*)_videoFrame,
_videoCodecCtx->pix_fmt,
_videoCodecCtx->width,
_videoCodecCtx->height);
}
KxVideoFrame *frame = [self handleVideoFrame];
if (frame) {
[result addObject:frame];
_position = frame.position;
decodedDuration += frame.duration;
if (decodedDuration > minDuration)
finished = YES;
}
} else {
count++;
}
if (0 == len)
break;
pktSize -= len;
}
}
av_free_packet(&packet);
}
} while (totalDuration > 0);
_reading = [NSNumber numberWithInt:0];
return result;
}
}
return result;
With the application in the background on iOS 11,
Execution of AUGraphInitialize () fails,
Error code 560557684 is returned and audio can not be played.
AUGraphInitialize () was successful on iOS 10 in the same situation.
Is this a bug in iOS 11?
Is there planning to fix apple in this case?
If it is not a bug,
With iOS 11 the application is in the background,
What kind of implementation should be done to make AUGraphInitialize () succeed?
Please give me hints!
Describe the source of this error case below.
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
if (audioSession == nil) {
LOGE("AVAudioSession : sharedInstance() error.");
}
NSError *audioSessionError = nil;
BOOL ret = [audioSession setActive:NO error:&audioSessionError];
if (ret == false) {
LOGE("AVAudioSession : setActive() error. code = %d", (int)audioSessionError.code);
}
NSTimeInterval bufferDuration = 2048 / 44100;
ret = [audioSession setPreferredIOBufferDuration:bufferDuration error:&audioSessionError];
if (ret == false) {
LOGE("AVAudioSession : setPreferredIOBufferDuration() error. code = %d", (int)audioSessionError.code);
}
ret = [audioSession setCategory:AVAudioSessionCategoryPlayback
error:&audioSessionError];
if (ret == false) {
LOGE("AVAudioSession : setCategory() error. code = %d", (int)audioSessionError.code);
}
[audioSession setActive:YES error:&audioSessionError];
OSStatus err = NewAUGraph(&mGraph);
if ( err != noErr ) {
LOGE("AUGraph : NewAUGraph() error. code = %d", (int)err);
}
err = AUGraphOpen(mGraph);
if ( err != noErr ) {
LOGE("AUGraph : AUGraphOpen() error. code = %d", (int)err);
}
AudioComponentDescription output_desc;
output_desc.componentType = kAudioUnitType_Output;
output_desc.componentSubType = kAudioUnitSubType_RemoteIO;
output_desc.componentManufacturer = kAudioUnitManufacturer_Apple;
output_desc.componentFlags = 0;
output_desc.componentFlagsMask = 0;
AUNode outputNode;
err = AUGraphAddNode(mGraph, &output_desc, &outputNode);
if ( err != noErr ) {
LOGE("AUGraph : AUGraphAddNode() error. code = %d", (int)err);
}
err = AUGraphNodeInfo(mGraph, outputNode, NULL, &mOutUnit);
if ( err != noErr ) {
LOGE("AUGraph : AUGraphNodeInfo() error. code = %d", (int)err);
}
AURenderCallbackStruct callback;
callback.inputProc = _renderCallback;
callback.inputProcRefCon = (__bridge void*)self;
err = AUGraphSetNodeInputCallback(mGraph,
outputNode,
0,
&callback);
if ( err != noErr ) {
LOGE("AUGraph : AUGraphSetNodeInputCallback() error. code = %d", (int)err);
}
AudioStreamBasicDescription outputFormat;
UInt32 size = sizeof(AudioStreamBasicDescription);
err = AudioUnitGetProperty( mOutUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outputFormat, &size );
if ( err != noErr ) {
LOGE("AUGraph : AudioUnitGetProperty() error. code = %d", (int)err);
return nil;
}
outputFormat.mSampleRate = 44100.0f;
err = AudioUnitSetProperty(mOutUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &outputFormat, size);
if ( err != noErr ) {
LOGE("AUGraph : AudioUnitSetProperty() error. code = %d", (int)err);
}
err = AUGraphConnectNodeInput(mGraph,
outputNode, 0,
outputNode, 1
);
if ( err != noErr ) {
LOGE("AUGraph : AUGraphConnectNodeInput() error. code = %d", (int)err);
}
err = AUGraphInitialize(mGraph);
if ( err != noErr ) {
LOGE("AUGraph : AUGraphInitialize() error. code = %d", (int)err);
}
So I have an app that when you press the numbers on your keyboard on top, it normally types the symbols.
But with the app it types the numbers.
But if I run it in xcode, everything works fine, but when i open the app outside of xcode it doesn't work.
I have the newest update of mac os x and xcode.
Video:
https://youtu.be/67hRybEmJJY
Can anybody help me please?
CGEventRef KeyHandler(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
UniCharCount actualStringLength;
UniCharCount maxStringLength = 1;
UniChar chars[3];
CGEventKeyboardGetUnicodeString(event, maxStringLength, &actualStringLength, chars);
NSString *rusLetters1 = #"&";
if (chars[0] == [rusLetters1 characterAtIndex:0]) {
chars[0] = '1';
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters2 = #"é";
if (chars[0] == [rusLetters2 characterAtIndex:0]) {
chars[0] = '2';
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters3 = #"\"";
if (chars[0] == [rusLetters3 characterAtIndex:0]) {
chars[0] = '3';
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters4 = #"'";
if (chars[0] == [rusLetters4 characterAtIndex:0]) {
chars[0] = '4';
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters5 = #"(";
if (chars[0] == [rusLetters5 characterAtIndex:0]) {
chars[0] = '5';
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters6 = #"§";
if (chars[0] == [rusLetters6 characterAtIndex:0]) {
chars[0] = '6';
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters7 = #"è";
if (chars[0] == [rusLetters7 characterAtIndex:0]) {
chars[0] = '7';
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters8 = #"!";
if (chars[0] == [rusLetters8 characterAtIndex:0]) {
chars[0] = '8';
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters9 = #"ç";
if (chars[0] == [rusLetters9 characterAtIndex:0]) {
chars[0] = '9';
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters0 = #"à";
if (chars[0] == [rusLetters0 characterAtIndex:0]) {
chars[0] = '0';
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
//_________________________________________________________________________________________________________________
NSString *rusLetters11 = #"&";
if (chars[0] == '1') {
chars[0] = [rusLetters11 characterAtIndex:0];
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters12 = #"é";
if (chars[0] == '2') {
chars[0] = [rusLetters12 characterAtIndex:0];
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters13 = #"\"";
if (chars[0] == '3') {
chars[0] = [rusLetters13 characterAtIndex:0];
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters14 = #"'";
if (chars[0] == '4') {
chars[0] = [rusLetters14 characterAtIndex:0];
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters15 = #"(";
if (chars[0] == '5') {
chars[0] = [rusLetters15 characterAtIndex:0];
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters16 = #"§";
if (chars[0] == '6') {
chars[0] = [rusLetters16 characterAtIndex:0];
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters17 = #"è";
if (chars[0] == '7') {
chars[0] = [rusLetters17 characterAtIndex:0];
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters18 = #"!";
if (chars[0] == '8') {
chars[0] = [rusLetters18 characterAtIndex:0];
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters19 = #"ç";
if (chars[0] == '9') {
chars[0] = [rusLetters19 characterAtIndex:0];
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
NSString *rusLetters10 = #"à";
if (chars[0] == '0') {
chars[0] = [rusLetters10 characterAtIndex:0];
CGEventKeyboardSetUnicodeString(event, 1, chars);
return event;
}
return event;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
CFMachPortRef eventTap;
CGEventMask eventMask;
CFRunLoopSourceRef runLoopSource;
eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, eventMask, KeyHandler, NULL);
if (!eventTap) {
exit(1);
}
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
CFRunLoopRun();
}
Here's what I would do. There are many ways to calculate the modified character, this is one of them.
#import "AppDelegate.h"
#interface AppDelegate ()
#property (assign) CFMachPortRef myEventTap;
#property (assign) CFRunLoopSourceRef myRunLoopSource;
#end
#implementation AppDelegate
CGEventRef KeyHandler(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
// don't modify keys on the numeric keypad
CGEventFlags flags = CGEventGetFlags(event);
if (flags & kCGEventFlagMaskNumericPad)
return event;
// get the typed character
UniCharCount actualStringLength;
UniChar chars[3];
CGEventKeyboardGetUnicodeString(event, 3, &actualStringLength, chars);
// uncomment this line to log the typed character, the modifier flags (Shift, Option, etc.) and the key code (number of the key on the keyboard)
NSLog(#"%C %llX %lld", chars[0], flags, CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode));
if (actualStringLength == 1) {
// map the character from string1 to string2 and vice versa
NSString *string1 = #"&é\"'(§è!çà";
NSString *string2 = #"1234567890";
NSString *typedString = [NSString stringWithCharacters:chars length:1];
// find the index of the typed character in string1
NSRange range = [string1 rangeOfString:typedString];
if (range.location != NSNotFound)
// get the character in string2 at the same index
chars[0] = [string2 characterAtIndex:range.location];
else {
// find the index of the typed character in string2
range = [string2 rangeOfString:typedString];
if (range.location != NSNotFound)
// get the character in string1 at the same index
chars[0] = [string1 characterAtIndex:range.location];
}
// if the character was found, replace the character in the event
if (range.location != NSNotFound)
CGEventKeyboardSetUnicodeString(event, 1, chars);
}
return event;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// create an event tap, we want the key down and key up events
CGEventMask eventMask = CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp);
self.myEventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, eventMask, KeyHandler, NULL);
if (self.myEventTap) {
// create a runloop source
self.myRunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.myEventTap, 0);
// add it to the current run loop
CFRunLoopAddSource(CFRunLoopGetCurrent(), self.myRunLoopSource, kCFRunLoopCommonModes);
}
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// remove the event tap
if (self.myRunLoopSource) {
CFRunLoopSourceInvalidate(self.myRunLoopSource);
CFRelease(self.myRunLoopSource);
}
if (self.myEventTap)
CFRelease(self.myEventTap);
}
#end
I've had a bit of trouble finding any information on this and all the code samples I come across are based on the match ending in a tie for all players. In my 2 player turn based game I want to be able to end the match with a winner and loser. With the below code I've written the match always ends with the same result for both players, if its a win then both player 1 and 2 win, if its a loss both player 1 and 2 loose... any help? Thank you.
if (gameOver == true) {
if (GameWinner == 0) {
GKTurnBasedParticipant *player0 = [currentMatch.participants objectAtIndex:0];
player0.matchOutcome = GKTurnBasedMatchOutcomeWon;
GKTurnBasedParticipant *player1 = [currentMatch.participants objectAtIndex:1];
player1.matchOutcome = GKTurnBasedMatchOutcomeLost;
[currentMatch endMatchInTurnWithMatchData:data completionHandler:^(NSError *error) {
if (error) {
NSLog(#"%#", error);
}
}];
testlabel.text = #"Player 1 Wins!";
} else if (GameWinner == 1) {
GKTurnBasedParticipant *player0 = [currentMatch.participants objectAtIndex:0];
player0.matchOutcome = GKTurnBasedMatchOutcomeLost;
GKTurnBasedParticipant *player1 = [currentMatch.participants objectAtIndex:1];
player1.matchOutcome = GKTurnBasedMatchOutcomeWon;
[currentMatch endMatchInTurnWithMatchData:data completionHandler:^(NSError *error) {
if (error) {
NSLog(#"%#", error);
}
}];
testlabel.text = #"Player 2 Wins!";
} else if (GameWinner == 2) {
for (GKTurnBasedParticipant *part in currentMatch.participants) {
part.matchOutcome = GKTurnBasedMatchOutcomeTied;
}
[currentMatch endMatchInTurnWithMatchData:data completionHandler:^(NSError *error) {
if (error) {
NSLog(#"%#", error);
}
}];
testlabel.text = #"Tie Game!";
} else {
testlabel.text = #"Your turn is over.";
}
This sounds similar to this SO Question, try:
GKTurnBasedParticipant *curr = currentMatch.currentParticipant;
NSUInteger currentIndex = [currentMatch.participants indexOfObject:currentMatch.currentParticipant];
NSUInteger nextIndex = (currentIndex + 1) % [currentMatch.participants count];
GKTurnBasedParticipant *next = [currentMatch.participants objectAtIndex:nextIndex];
if (currScore < otherScore)
{
// Curr player lost
curr.matchOutcome = GKTurnBasedMatchOutcomeLost;
next.matchOutcome = GKTurnBasedMatchOutcomeWon;
}
else if (currScore == otherScore)
{
// Tied
curr.matchOutcome = GKTurnBasedMatchOutcomeTied;
next.matchOutcome = GKTurnBasedMatchOutcomeTied;
}
else
{
// Won
curr.matchOutcome = GKTurnBasedMatchOutcomeWon;
next.matchOutcome = GKTurnBasedMatchOutcomeLost;
}