天天看點

IOS開發程式設計中的問題小結(二)

1、IOS中單例模式的使用及出現的問題        

單例模式是在代碼間共享資料而不需要手動傳遞參數的一種最有用的方法。關于單例和其他設計模式,請參考這本書:《Cocoa design pattern》

         單例模式的具體實作,請參見博文http://blog.csdn.net/kmyhy/article/details/8715764

         由于現在IOS7系統在生成工程時都是預設的ARC模式,是以在使用單例模式時,特别要注意ARC和非ARC的不同。

        而我在使用單例模式傳遞全局變量時,發現:在OC類中能正常使用,但是如果和C++混合程式設計,即在C++類中使用OC編寫的全局變量單例模式類時,會出現記憶體不良增長的問題,即每使用一下單例模式類的成員變量,記憶體都會增加一點,且一直不釋放,還沒找到原因,如果哪位大神知道,請分享下。

2、使用AudioQueueNewInput出現記憶體洩露的問題

在IOS7中使用Audio Queue進行錄放音時,如果是使用OC類函數調用 Audio Queue的接口,就會遇到類型強制轉換的問題。

比如在oc類中調用函數AudioQueueNewInput的方式

AudioQueueNewInput(&iRecordDescription,

                                           MyInputBufferHandler,

                                          (__bridge void*)self,

                                          NULL,

                                          NULL,

                                          0,

                                          &iReceiveQueue);

其中,self必須經過強制類型轉換才能使用(__bridge void*)self,當然,類型轉換在不同情況下有不同轉換方式,其他可參見博文http://blog.sina.com.cn/s/blog_65a8ab5d0101c8k2.html

但是,這樣編譯雖然可以通過,但如果用Instruments軟體進行檢測時會發現存在記憶體洩露的問題。

後來,我改為在C++類中調用函數,才避免了這個問題。

AudioQueueNewInput(&iRecordDescription,

                                           MyInputBufferHandler,

                                          this,

                                          NULL,

                                          NULL,

                                          0,

                                          &iReceiveQueue);

3、IOS中區分iPhone/iPad的三種方法

1)使用  UI_USER_INTERFACE_IDIOM() 進行區分  (ios 3.2 >=)  無法區分iphone和ipod

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {

       // <define your constants here>

    } else {

      //  <define your constants here>

    }

區分目前UI_USER_INTERFACE_IDIOM()有2個傳回值

UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad    //ipad

UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone    //ipad

2)使用 UIDevice.model 進行區分  (ios 2.0 >=)

    NSString *deviceType = [UIDevice currentDevice].model;

    if([deviceType isEqualToString:@"iPhone"]) {

        //iPhone

    }

    else if([deviceType isEqualToString:@"iPod touch"]) {

        //iPod Touch

    }

    else {

        //iPad

    }

3)使用系統的一個函數sysctlbyname 來擷取裝置名稱

- (NSString *) platformString

{

    size_t size;

    sysctlbyname("hw.machine", NULL, &size, NULL, 0);

    char *machine = malloc(size);

    sysctlbyname("hw.machine", machine, &size, NULL, 0);

    NSString *platform = [NSString stringWithUTF8String:machine];

    free(machine);

    if ([platform isEqualToString:@"iPhone1,1"])    return @"iPhone 1G";

    if ([platform isEqualToString:@"iPhone1,2"])    return @"iPhone 3G";

    if ([platform isEqualToString:@"iPhone2,1"])    return @"iPhone 3GS";

    if ([platform isEqualToString:@"iPhone3,1"])    return @"iPhone 4";

    if ([platform isEqualToString:@"iPhone3,3"])    return @"Verizon iPhone 4";

    if ([platform isEqualToString:@"iPod1,1"])      return @"iPod Touch 1G";

    if ([platform isEqualToString:@"iPod2,1"])      return @"iPod Touch 2G";

    if ([platform isEqualToString:@"iPod3,1"])      return @"iPod Touch 3G";

    if ([platform isEqualToString:@"iPod4,1"])      return @"iPod Touch 4G";

    if ([platform isEqualToString:@"iPad1,1"])      return @"iPad";

    if ([platform isEqualToString:@"iPad2,1"])      return @"iPad 2 (WiFi)";

    if ([platform isEqualToString:@"iPad2,2"])      return @"iPad 2 (GSM)";

    if ([platform isEqualToString:@"iPad2,3"])      return @"iPad 2 (CDMA)";

    if ([platform isEqualToString:@"i386"])         return @"Simulator";

    return @"";

}

4、IOS檢測耳機插入/拔出的問題

我們使用的音樂播放器,比如酷我,在耳機從手機中拔出時,會停止播放。這個功能的實作,手機得能檢測到耳機的拔出。

實際上,在IOS6以前都留出了接口來檢測耳機的插入/拔出。

這個是通過監聽AudioSession的RouteChange事件然後判斷耳機狀态實作的。實作步驟分為兩步,首先注冊監聽函數,然後再監聽函數中判斷耳機狀态。

注冊監聽函數:

 AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange,  

                                     audioRouteChangeListenerCallback,  

                                    self);  

然後就是監聽函數audioRouteChangeListenerCallback的實作,詳情請參見http://blog.csdn.net/onlyou930/article/details/7442596

當然,這是指在軟體運作過程中去檢測插入/拔出。我們通常還會需要在開機時去檢測是否有耳機。其檢測方法如下:

1.       檢測聲音輸入裝置

- (BOOL)hasMicphone {  

 return [[AVAudioSession sharedInstance] inputIsAvailable];} 

2.       檢測聲音輸出裝置

 - (BOOL)hasHeadset {  

      #if TARGET_IPHONE_SIMULATOR  

      #warning *** Simulator mode: audio session code works only on a device  

      return NO;  

      #else   

      CFStringRef route;  

      UInt32 propertySize = sizeof(CFStringRef);  

      AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &propertySize, &route);  

      if((route == NULL) || (CFStringGetLength(route) == 0)){  

        // Silent Mode  

       NSLog(@"AudioRoute: SILENT, do nothing!");  

       } else {  

       NSString* routeStr = (NSString*)route;  

       NSLog(@"AudioRoute: %@", routeStr);  

        NSRange headphoneRange = [routeStr rangeOfString : @"Headphone"];  

        NSRange headsetRange = [routeStr rangeOfString : @"Headset"];  

       if (headphoneRange.location != NSNotFound) {  

          return YES;  

       } else if(headsetRange.location != NSNotFound) {  

            return YES;  

       }  

   }  

     return NO;  

 #endif  

}  

但是,蘋果在IOS7以後,很多接口都被封了,比如AudioSessionGetProperty,網上暫時還沒找到替代的方法。而且,IOS7以後,蘋果對于耳機的檢測更為細緻,分為帶耳麥和不帶耳麥,其檢測方法貌似和耳麥的阻抗有關,比如有的耳機帶耳麥,但耳麥的阻抗比較小的話,會認為沒帶,當要使用耳麥進行錄音時,會預設為蘋果裝置自帶的耳麥。